mirror of
https://github.com/thegeeklab/drone-yaml.git
synced 2024-11-25 03:20:39 +00:00
refactor: remove unused components
This commit is contained in:
parent
8e595fca5b
commit
b1275997d7
@ -1,47 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
name: build
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: backend
|
|
||||||
image: golang:1.11
|
|
||||||
commands:
|
|
||||||
- go build
|
|
||||||
- go test -v
|
|
||||||
|
|
||||||
- name: frontend
|
|
||||||
image: node
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm run test
|
|
||||||
- npm run lint
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
image: redis:latest
|
|
||||||
ports:
|
|
||||||
- 6379
|
|
||||||
volumes:
|
|
||||||
- name: foo
|
|
||||||
path: /bar
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- name: foo
|
|
||||||
temp: {}
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: notify
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: notify
|
|
||||||
image: plugins/slack
|
|
||||||
settings:
|
|
||||||
room: general
|
|
||||||
token:
|
|
||||||
from_secret: token
|
|
||||||
|
|
||||||
node:
|
|
||||||
disk: ssd
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- build
|
|
@ -1,22 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
name: default
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: backend
|
|
||||||
image: golang:1.11
|
|
||||||
commands:
|
|
||||||
- go build
|
|
||||||
- go test -v
|
|
||||||
|
|
||||||
- name: frontend
|
|
||||||
image: node
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm run test
|
|
||||||
- npm run lint
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
image: redis:latest
|
|
||||||
ports:
|
|
||||||
- 6379
|
|
@ -1,48 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
yaml string
|
|
||||||
image string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
yaml: "bar",
|
|
||||||
image: "bar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "{ image: foo }",
|
|
||||||
image: "foo",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
in := []byte(test.yaml)
|
|
||||||
out := new(Build)
|
|
||||||
err := yaml.Unmarshal(in, out)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if got, want := out.Image, test.image; got != want {
|
|
||||||
t.Errorf("Want image %q, got %q", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuildError(t *testing.T) {
|
|
||||||
in := []byte("[]")
|
|
||||||
out := new(Build)
|
|
||||||
err := yaml.Unmarshal(in, out)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expect unmarshal error")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
// default name of the clone step.
|
|
||||||
const cloneStepName = "clone"
|
|
||||||
|
|
||||||
// helper function returns the preferred clone image
|
|
||||||
// based on the target architecture.
|
|
||||||
func cloneImage(src *yaml.Pipeline) string {
|
|
||||||
switch {
|
|
||||||
case src.Platform.OS == "linux" && src.Platform.Arch == "arm":
|
|
||||||
return "drone/git:linux-arm"
|
|
||||||
case src.Platform.OS == "linux" && src.Platform.Arch == "arm64":
|
|
||||||
return "drone/git:linux-arm64"
|
|
||||||
case src.Platform.OS == "windows" && src.Platform.Version == "1903":
|
|
||||||
return "drone/git:windows-1903-amd64"
|
|
||||||
case src.Platform.OS == "windows" && src.Platform.Version == "1809":
|
|
||||||
return "drone/git:windows-1809-amd64"
|
|
||||||
case src.Platform.OS == "windows" && src.Platform.Version == "1803":
|
|
||||||
return "drone/git:windows-1803-amd64"
|
|
||||||
case src.Platform.OS == "windows" && src.Platform.Version == "1709":
|
|
||||||
return "drone/git:windows-1709-amd64"
|
|
||||||
case src.Platform.OS == "windows":
|
|
||||||
return "drone/git:windows-1809-amd64"
|
|
||||||
default:
|
|
||||||
return "drone/git"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function configures the clone depth parameter,
|
|
||||||
// specific to the clone plugin.
|
|
||||||
//
|
|
||||||
// TODO(bradrydzewski) rename to setupCloneParams
|
|
||||||
func setupCloneDepth(src *yaml.Pipeline, dst *engine.Step) {
|
|
||||||
if depth := src.Clone.Depth; depth > 0 {
|
|
||||||
dst.Envs["PLUGIN_DEPTH"] = strconv.Itoa(depth)
|
|
||||||
}
|
|
||||||
if skipVerify := src.Clone.SkipVerify; skipVerify {
|
|
||||||
dst.Envs["GIT_SSL_NO_VERIFY"] = "true"
|
|
||||||
dst.Envs["PLUGIN_SKIP_VERIFY"] = "true"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function configures the .git-clone credentials
|
|
||||||
// file. The file is mounted into the container, pointed
|
|
||||||
// to by XDG_CONFIG_HOME
|
|
||||||
// see https://git-scm.com/docs/git-credential-store
|
|
||||||
func setupCloneCredentials(spec *engine.Spec, dst *engine.Step, data []byte) {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO(bradrydzewski) we may need to update the git
|
|
||||||
// clone plugin to configure the git credential store.
|
|
||||||
dst.Files = append(dst.Files, &engine.FileMount{
|
|
||||||
Name: ".git-credentials",
|
|
||||||
Path: "/root/.git-credentials",
|
|
||||||
})
|
|
||||||
spec.Files = append(spec.Files, &engine.File{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
Name: ".git-credentials",
|
|
||||||
},
|
|
||||||
Data: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function creates a default container configuration
|
|
||||||
// for the clone stage. The clone stage is automatically
|
|
||||||
// added to each pipeline.
|
|
||||||
func createClone(src *yaml.Pipeline) *yaml.Container {
|
|
||||||
return &yaml.Container{
|
|
||||||
Name: cloneStepName,
|
|
||||||
Image: cloneImage(src),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCloneImage(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
platform yaml.Platform
|
|
||||||
image string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "linux", Arch: "amd64"},
|
|
||||||
image: "drone/git",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "linux", Arch: "arm"},
|
|
||||||
image: "drone/git:linux-arm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "linux", Arch: "arm64"},
|
|
||||||
image: "drone/git:linux-arm64",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "windows", Arch: "amd64", Version: "1709"},
|
|
||||||
image: "drone/git:windows-1709-amd64",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "windows", Arch: "amd64", Version: "1809"},
|
|
||||||
image: "drone/git:windows-1809-amd64",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "windows", Arch: "amd64", Version: "1903"},
|
|
||||||
image: "drone/git:windows-1903-amd64",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{OS: "windows", Arch: "amd64"},
|
|
||||||
image: "drone/git:windows-1809-amd64",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
platform: yaml.Platform{},
|
|
||||||
image: "drone/git",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
pipeline := &yaml.Pipeline{Platform: test.platform}
|
|
||||||
image := cloneImage(pipeline)
|
|
||||||
if got, want := image, test.image; got != want {
|
|
||||||
t.Errorf("Want clone image %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetupCloneDepth(t *testing.T) {
|
|
||||||
// test zero depth
|
|
||||||
src := &yaml.Pipeline{
|
|
||||||
Clone: yaml.Clone{
|
|
||||||
Depth: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dst := &engine.Step{
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
setupCloneDepth(src, dst)
|
|
||||||
if _, ok := dst.Envs["PLUGIN_DEPTH"]; ok {
|
|
||||||
t.Errorf("Expect depth ignored when zero value")
|
|
||||||
}
|
|
||||||
|
|
||||||
// test non-zero depth
|
|
||||||
src = &yaml.Pipeline{
|
|
||||||
Clone: yaml.Clone{
|
|
||||||
Depth: 50,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dst = &engine.Step{
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
setupCloneDepth(src, dst)
|
|
||||||
if got, want := dst.Envs["PLUGIN_DEPTH"], "50"; got != want {
|
|
||||||
t.Errorf("Expect depth %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetupCloneSkipVerify(t *testing.T) {
|
|
||||||
// test zero depth
|
|
||||||
src := &yaml.Pipeline{
|
|
||||||
Clone: yaml.Clone{
|
|
||||||
SkipVerify: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dst := &engine.Step{
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
setupCloneDepth(src, dst)
|
|
||||||
if _, ok := dst.Envs["PLUGIN_SKIP_VERIFY"]; ok {
|
|
||||||
t.Errorf("Expect skip verify not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// test non-zero depth
|
|
||||||
src = &yaml.Pipeline{
|
|
||||||
Clone: yaml.Clone{
|
|
||||||
SkipVerify: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dst = &engine.Step{
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
setupCloneDepth(src, dst)
|
|
||||||
if got, want := dst.Envs["PLUGIN_SKIP_VERIFY"], "true"; got != want {
|
|
||||||
t.Errorf("Expect skip verify %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,317 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/image"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Compiler compiles the pipeline configuration to an
|
|
||||||
// intermediate representation that can be executed by
|
|
||||||
// the Drone runtime engine.
|
|
||||||
type Compiler struct {
|
|
||||||
// GitCredentialsFunc returns a .git-credentials file
|
|
||||||
// that can be used by the default clone step to
|
|
||||||
// authenticate to the remote repository.
|
|
||||||
GitCredentialsFunc func() []byte
|
|
||||||
|
|
||||||
// NetrcFunc returns a .netrc file that can be used by
|
|
||||||
// the default clone step to authenticate to the remote
|
|
||||||
// repository.
|
|
||||||
NetrcFunc func() []byte
|
|
||||||
|
|
||||||
// PrivilegedFunc returns true if the container should
|
|
||||||
// be started in privileged mode. The intended use is
|
|
||||||
// for plugins that run Docker-in-Docker. This will be
|
|
||||||
// deprecated in a future release.
|
|
||||||
PrivilegedFunc func(*yaml.Container) bool
|
|
||||||
|
|
||||||
// SkipFunc returns true if the step should be skipped.
|
|
||||||
// The skip function can be used to evaluate the when
|
|
||||||
// clause of each step, and return true if it should
|
|
||||||
// be skipped.
|
|
||||||
SkipFunc func(*yaml.Container) bool
|
|
||||||
|
|
||||||
// TransformFunc can be used to modify the compiled
|
|
||||||
// output prior to completion. This can be useful when
|
|
||||||
// you need to programatically modify the output,
|
|
||||||
// set defaults, etc.
|
|
||||||
TransformFunc func(*engine.Spec)
|
|
||||||
|
|
||||||
// WorkspaceFunc can be used to set the workspace volume
|
|
||||||
// that is created for the entire pipeline. The primary
|
|
||||||
// use case for this function is running local builds,
|
|
||||||
// where the workspace is mounted to the host machine
|
|
||||||
// working directory.
|
|
||||||
WorkspaceFunc func(*engine.Spec)
|
|
||||||
|
|
||||||
// WorkspaceMountFunc can be used to override the default
|
|
||||||
// workspace volume mount.
|
|
||||||
WorkspaceMountFunc func(step *engine.Step, base, path, full string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile returns an intermediate representation of the
|
|
||||||
// pipeline configuration that can be executed by the
|
|
||||||
// Drone runtime engine.
|
|
||||||
func (c *Compiler) Compile(from *yaml.Pipeline) *engine.Spec {
|
|
||||||
namespace := rand.String()
|
|
||||||
|
|
||||||
isSerial := true
|
|
||||||
for _, step := range from.Steps {
|
|
||||||
if len(step.DependsOn) != 0 {
|
|
||||||
isSerial = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: namespace,
|
|
||||||
Name: namespace,
|
|
||||||
Namespace: namespace,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"io.drone.pipeline.name": from.Name,
|
|
||||||
"io.drone.pipeline.kind": from.Kind,
|
|
||||||
"io.drone.pipeline.type": from.Type,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Platform: engine.Platform{
|
|
||||||
OS: from.Platform.OS,
|
|
||||||
Arch: from.Platform.Arch,
|
|
||||||
Version: from.Platform.Version,
|
|
||||||
Variant: from.Platform.Variant,
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerConfig{},
|
|
||||||
Files: nil,
|
|
||||||
Secrets: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the default workspace path. If a container
|
|
||||||
// does not specify a working directory it defaults
|
|
||||||
// to the workspace path.
|
|
||||||
base, dir, workspace := createWorkspace(from)
|
|
||||||
|
|
||||||
// create the default workspace volume definition.
|
|
||||||
// the volume will be mounted to each container in
|
|
||||||
// the pipeline.
|
|
||||||
c.setupWorkspace(spec)
|
|
||||||
|
|
||||||
// for each volume defined in the yaml configuration
|
|
||||||
// file, convert to a runtime volume and append to the
|
|
||||||
// specification.
|
|
||||||
for _, from := range from.Volumes {
|
|
||||||
to := &engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: from.Name,
|
|
||||||
Namespace: namespace,
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if from.EmptyDir != nil {
|
|
||||||
// if the yaml configuration specifies an empty
|
|
||||||
// directory volume (data volume) or an in-memory
|
|
||||||
// file system.
|
|
||||||
to.EmptyDir = &engine.VolumeEmptyDir{
|
|
||||||
Medium: from.EmptyDir.Medium,
|
|
||||||
SizeLimit: int64(from.EmptyDir.SizeLimit),
|
|
||||||
}
|
|
||||||
} else if from.HostPath != nil {
|
|
||||||
// if the yaml configuration specifies a bind
|
|
||||||
// mount to the host machine.
|
|
||||||
to.HostPath = &engine.VolumeHostPath{
|
|
||||||
Path: from.HostPath.Path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spec.Docker.Volumes = append(spec.Docker.Volumes, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !from.Clone.Disable {
|
|
||||||
src := createClone(from)
|
|
||||||
dst := createStep(spec, src)
|
|
||||||
dst.Docker.PullPolicy = engine.PullIfNotExists
|
|
||||||
setupCloneDepth(from, dst)
|
|
||||||
setupCloneCredentials(spec, dst, c.gitCredentials())
|
|
||||||
setupWorkingDir(src, dst, workspace)
|
|
||||||
setupWorkspaceEnv(dst, base, dir, workspace)
|
|
||||||
c.setupWorkspaceMount(dst, base, dir, workspace)
|
|
||||||
spec.Steps = append(spec.Steps, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each pipeline service defined in the yaml
|
|
||||||
// configuration file, convert to a runtime step
|
|
||||||
// and append to the specification.
|
|
||||||
for _, service := range from.Services {
|
|
||||||
step := createStep(spec, service)
|
|
||||||
// note that all services are automatically
|
|
||||||
// set to run in detached mode.
|
|
||||||
step.Detach = true
|
|
||||||
setupWorkingDir(service, step, workspace)
|
|
||||||
setupWorkspaceEnv(step, base, dir, workspace)
|
|
||||||
c.setupWorkspaceMount(step, base, dir, workspace)
|
|
||||||
// if the skip callback function returns true,
|
|
||||||
// modify the runtime step to never execute.
|
|
||||||
if c.skip(service) {
|
|
||||||
step.RunPolicy = engine.RunNever
|
|
||||||
}
|
|
||||||
// if the step is a plugin and should be executed
|
|
||||||
// in privileged mode, set the privileged flag.
|
|
||||||
if c.privileged(service) {
|
|
||||||
step.Docker.Privileged = true
|
|
||||||
}
|
|
||||||
// if the clone step is enabled, the service should
|
|
||||||
// not start until the clone step is complete. Add
|
|
||||||
// the clone step as a dependency in the graph.
|
|
||||||
if isSerial == false && from.Clone.Disable == false {
|
|
||||||
step.DependsOn = append(step.DependsOn, cloneStepName)
|
|
||||||
}
|
|
||||||
spec.Steps = append(spec.Steps, step)
|
|
||||||
}
|
|
||||||
|
|
||||||
// rename will store a list of container names
|
|
||||||
// that should be mapped to their temporary alias.
|
|
||||||
rename := map[string]string{}
|
|
||||||
|
|
||||||
// for each pipeline step defined in the yaml
|
|
||||||
// configuration file, convert to a runtime step
|
|
||||||
// and append to the specification.
|
|
||||||
for _, container := range from.Steps {
|
|
||||||
var step *engine.Step
|
|
||||||
switch {
|
|
||||||
case container.Build != nil:
|
|
||||||
step = createBuildStep(spec, container)
|
|
||||||
rename[container.Build.Image] = step.Metadata.UID
|
|
||||||
default:
|
|
||||||
step = createStep(spec, container)
|
|
||||||
}
|
|
||||||
setupWorkingDir(container, step, workspace)
|
|
||||||
setupWorkspaceEnv(step, base, dir, workspace)
|
|
||||||
c.setupWorkspaceMount(step, base, dir, workspace)
|
|
||||||
// if the skip callback function returns true,
|
|
||||||
// modify the runtime step to never execute.
|
|
||||||
if c.skip(container) {
|
|
||||||
step.RunPolicy = engine.RunNever
|
|
||||||
}
|
|
||||||
// if the step is a plugin and should be executed
|
|
||||||
// in privileged mode, set the privileged flag.
|
|
||||||
if c.privileged(container) {
|
|
||||||
step.Docker.Privileged = true
|
|
||||||
}
|
|
||||||
// if the clone step is enabled, the step should
|
|
||||||
// not start until the clone step is complete. If
|
|
||||||
// no dependencies are defined, at a minimum, the
|
|
||||||
// step depends on the initial clone step completing.
|
|
||||||
if isSerial == false && from.Clone.Disable == false && len(step.DependsOn) == 0 {
|
|
||||||
step.DependsOn = append(step.DependsOn, cloneStepName)
|
|
||||||
}
|
|
||||||
spec.Steps = append(spec.Steps, step)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the pipeline includes any build and publish
|
|
||||||
// steps we should create an entry for the host
|
|
||||||
// machine docker socket.
|
|
||||||
if spec.Docker != nil && len(rename) > 0 {
|
|
||||||
v := &engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: "_docker_socket",
|
|
||||||
Namespace: namespace,
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
HostPath: &engine.VolumeHostPath{
|
|
||||||
Path: "/var/run/docker.sock",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec.Docker.Volumes = append(spec.Docker.Volumes, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// images created during the pipeline are assigned a
|
|
||||||
// random alias. All references to the origin image
|
|
||||||
// name must be changed to the alias.
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
for k, v := range rename {
|
|
||||||
if image.MatchTag(step.Docker.Image, k) {
|
|
||||||
img := image.Trim(step.Docker.Image) + ":" + v
|
|
||||||
step.Docker.Image = image.Expand(img)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// executes user-defined transformations before the
|
|
||||||
// final specification is returned.
|
|
||||||
if c.TransformFunc != nil {
|
|
||||||
c.TransformFunc(spec)
|
|
||||||
}
|
|
||||||
|
|
||||||
return spec
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a .git-credentials file. If the user-defined
|
|
||||||
// function is nil, a nil credentials file is returned.
|
|
||||||
func (c *Compiler) gitCredentials() []byte {
|
|
||||||
if c.GitCredentialsFunc != nil {
|
|
||||||
return c.GitCredentialsFunc()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a .netrc file. If the user-defined function is
|
|
||||||
// nil, a nil netrc file is returned.
|
|
||||||
func (c *Compiler) netrc() []byte {
|
|
||||||
if c.NetrcFunc != nil {
|
|
||||||
return c.NetrcFunc()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the step should be executed in privileged
|
|
||||||
// mode. If the user-defined privileged function is nil,
|
|
||||||
// a default value of false is returned.
|
|
||||||
func (c *Compiler) privileged(container *yaml.Container) bool {
|
|
||||||
if c.PrivilegedFunc != nil {
|
|
||||||
return c.PrivilegedFunc(container)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the step should be skipped. If the
|
|
||||||
// user-defined skip function is nil, a defalt skip
|
|
||||||
// function is used that always returns true (i.e. do not skip).
|
|
||||||
func (c *Compiler) skip(container *yaml.Container) bool {
|
|
||||||
if c.SkipFunc != nil {
|
|
||||||
return c.SkipFunc(container)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) setupWorkspace(spec *engine.Spec) {
|
|
||||||
if c.WorkspaceFunc != nil {
|
|
||||||
c.WorkspaceFunc(spec)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
CreateWorkspace(spec)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) setupWorkspaceMount(step *engine.Step, base, path, full string) {
|
|
||||||
if c.WorkspaceMountFunc != nil {
|
|
||||||
c.WorkspaceMountFunc(step, base, path, full)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
MountWorkspace(step, base, path, full)
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
// Copyright the Drone Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func toIgnoreErr(from *yaml.Container) bool {
|
|
||||||
return strings.EqualFold(from.Failure, "ignore")
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPorts(from *yaml.Container) []*engine.Port {
|
|
||||||
var ports []*engine.Port
|
|
||||||
for _, port := range from.Ports {
|
|
||||||
ports = append(ports, toPort(port))
|
|
||||||
}
|
|
||||||
return ports
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPort(from *yaml.Port) *engine.Port {
|
|
||||||
return &engine.Port{
|
|
||||||
Port: from.Port,
|
|
||||||
Host: from.Host,
|
|
||||||
Protocol: from.Protocol,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toPullPolicy(from *yaml.Container) engine.PullPolicy {
|
|
||||||
switch strings.ToLower(from.Pull) {
|
|
||||||
case "always":
|
|
||||||
return engine.PullAlways
|
|
||||||
case "if-not-exists":
|
|
||||||
return engine.PullIfNotExists
|
|
||||||
case "never":
|
|
||||||
return engine.PullNever
|
|
||||||
default:
|
|
||||||
return engine.PullDefault
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toRunPolicy(from *yaml.Container) engine.RunPolicy {
|
|
||||||
onFailure := from.When.Status.Match("failure") && len(from.When.Status.Include) > 0
|
|
||||||
onSuccess := from.When.Status.Match("success")
|
|
||||||
switch {
|
|
||||||
case onFailure && onSuccess:
|
|
||||||
return engine.RunAlways
|
|
||||||
case onFailure:
|
|
||||||
return engine.RunOnFailure
|
|
||||||
case onSuccess:
|
|
||||||
return engine.RunOnSuccess
|
|
||||||
default:
|
|
||||||
return engine.RunNever
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toResources(from *yaml.Container) *engine.Resources {
|
|
||||||
if from.Resources == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &engine.Resources{
|
|
||||||
Limits: toResourceObject(from.Resources.Limits),
|
|
||||||
Requests: toResourceObject(from.Resources.Requests),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toResourceObject(from *yaml.ResourceObject) *engine.ResourceObject {
|
|
||||||
if from == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &engine.ResourceObject{
|
|
||||||
CPU: toCPUMillis(from.CPU),
|
|
||||||
Memory: int64(from.Memory),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toCPUMillis(f float64) int64 {
|
|
||||||
if f > 0 {
|
|
||||||
f *= 1000
|
|
||||||
}
|
|
||||||
return int64(f)
|
|
||||||
}
|
|
@ -1,162 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_toIgnoreErr(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
mode string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{"Ignore", true},
|
|
||||||
{"ignore", true},
|
|
||||||
{"fail", false},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
from := &yaml.Container{Failure: test.mode}
|
|
||||||
if toIgnoreErr(from) != test.want {
|
|
||||||
t.Errorf("unexpected ignore error for %s", test.mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_toPullPolicy(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
mode string
|
|
||||||
want engine.PullPolicy
|
|
||||||
}{
|
|
||||||
{"", engine.PullDefault},
|
|
||||||
{"always", engine.PullAlways},
|
|
||||||
{"if-not-exists", engine.PullIfNotExists},
|
|
||||||
{"never", engine.PullNever},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
from := &yaml.Container{Pull: test.mode}
|
|
||||||
if toPullPolicy(from) != test.want {
|
|
||||||
t.Errorf("unexpected pull policy for %s", test.mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_toRunPolicy(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
cond yaml.Condition
|
|
||||||
want engine.RunPolicy
|
|
||||||
}{
|
|
||||||
{yaml.Condition{}, engine.RunOnSuccess},
|
|
||||||
{yaml.Condition{Include: []string{"success"}}, engine.RunOnSuccess},
|
|
||||||
{yaml.Condition{Include: []string{"failure"}}, engine.RunOnFailure},
|
|
||||||
{yaml.Condition{Include: []string{"success", "failure"}}, engine.RunAlways},
|
|
||||||
{yaml.Condition{Exclude: []string{"success", "failure"}}, engine.RunNever},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
from := &yaml.Container{When: yaml.Conditions{Status: test.cond}}
|
|
||||||
if toRunPolicy(from) != test.want {
|
|
||||||
t.Errorf("unexpected pull policy for incude: %s, exclude: %s", test.cond.Include, test.cond.Exclude)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_toPorts(t *testing.T) {
|
|
||||||
from := &yaml.Container{
|
|
||||||
Ports: []*yaml.Port{
|
|
||||||
{
|
|
||||||
Port: 80,
|
|
||||||
Host: 8080,
|
|
||||||
Protocol: "TCP",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Port: 80,
|
|
||||||
Host: 0,
|
|
||||||
Protocol: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
a := toPorts(from)
|
|
||||||
b := []*engine.Port{
|
|
||||||
{
|
|
||||||
Port: 80,
|
|
||||||
Host: 8080,
|
|
||||||
Protocol: "TCP",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Port: 80,
|
|
||||||
Host: 0,
|
|
||||||
Protocol: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(a, b); diff != "" {
|
|
||||||
t.Errorf("Unexpected port conversion")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_toResources(t *testing.T) {
|
|
||||||
from := &yaml.Container{
|
|
||||||
Resources: nil,
|
|
||||||
}
|
|
||||||
if toResources(from) != nil {
|
|
||||||
t.Errorf("Expected nil resources")
|
|
||||||
}
|
|
||||||
|
|
||||||
// test what happens when limits are defined
|
|
||||||
// but reservations are nil.
|
|
||||||
|
|
||||||
from = &yaml.Container{
|
|
||||||
Resources: &yaml.Resources{
|
|
||||||
Limits: &yaml.ResourceObject{
|
|
||||||
Memory: yaml.BytesSize(1000),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
a := toResources(from)
|
|
||||||
b := &engine.Resources{
|
|
||||||
Limits: &engine.ResourceObject{
|
|
||||||
Memory: 1000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(a, b); diff != "" {
|
|
||||||
t.Errorf("Unexpected resource conversion")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
// test what happens when reservation and limits
|
|
||||||
// are both provided.
|
|
||||||
|
|
||||||
from = &yaml.Container{
|
|
||||||
Resources: &yaml.Resources{
|
|
||||||
Limits: &yaml.ResourceObject{
|
|
||||||
Memory: yaml.BytesSize(1000),
|
|
||||||
CPU: 4,
|
|
||||||
},
|
|
||||||
Requests: &yaml.ResourceObject{
|
|
||||||
Memory: yaml.BytesSize(2000),
|
|
||||||
CPU: 0.1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
a = toResources(from)
|
|
||||||
b = &engine.Resources{
|
|
||||||
Limits: &engine.ResourceObject{
|
|
||||||
Memory: 1000,
|
|
||||||
CPU: 4000,
|
|
||||||
},
|
|
||||||
Requests: &engine.ResourceObject{
|
|
||||||
Memory: 2000,
|
|
||||||
CPU: 100,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(a, b); diff != "" {
|
|
||||||
t.Errorf("Unexpected resource conversion")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/image"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DindFunc is a helper function that returns true
|
|
||||||
// if a container image (specifically a plugin) is
|
|
||||||
// a whitelisted dind container and should be executed
|
|
||||||
// in privileged mode.
|
|
||||||
func DindFunc(images []string) func(*yaml.Container) bool {
|
|
||||||
return func(container *yaml.Container) bool {
|
|
||||||
// privileged-by-default containers are only
|
|
||||||
// enabled for plugins steps that do not define
|
|
||||||
// commands, command, or entrypoint.
|
|
||||||
if len(container.Commands) > 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(container.Command) > 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(container.Entrypoint) > 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// if the container image matches any image
|
|
||||||
// in the whitelist, return true.
|
|
||||||
for _, img := range images {
|
|
||||||
a := img
|
|
||||||
b := container.Image
|
|
||||||
if image.Match(a, b) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDind(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
container *yaml.Container
|
|
||||||
privileged bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
container: &yaml.Container{Image: "plugins/docker"},
|
|
||||||
privileged: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
container: &yaml.Container{Image: "plugins/docker:latest"},
|
|
||||||
privileged: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
container: &yaml.Container{Image: "plugins/docker:1"},
|
|
||||||
privileged: true,
|
|
||||||
},
|
|
||||||
// no match
|
|
||||||
{
|
|
||||||
container: &yaml.Container{Image: "golang"},
|
|
||||||
privileged: false,
|
|
||||||
},
|
|
||||||
// dind containers cannot set entrypoint or command
|
|
||||||
{
|
|
||||||
container: &yaml.Container{
|
|
||||||
Image: "plugins/docker",
|
|
||||||
Command: []string{"docker run ..."},
|
|
||||||
},
|
|
||||||
privileged: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
container: &yaml.Container{
|
|
||||||
Image: "plugins/docker",
|
|
||||||
Entrypoint: []string{"docker run ..."},
|
|
||||||
},
|
|
||||||
privileged: false,
|
|
||||||
},
|
|
||||||
// dind containers cannot set commands
|
|
||||||
{
|
|
||||||
container: &yaml.Container{
|
|
||||||
Image: "plugins/docker",
|
|
||||||
Commands: []string{"docker run ..."},
|
|
||||||
},
|
|
||||||
privileged: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range tests {
|
|
||||||
images := []string{"plugins/docker", "plugins/ecr"}
|
|
||||||
privileged := DindFunc(images)(test.container)
|
|
||||||
if privileged != test.privileged {
|
|
||||||
t.Errorf("Want privileged %v at index %d", test.privileged, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
json "github.com/ghodss/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// helper funciton encodes an interface value as a string.
|
|
||||||
// this function assumes all types were unmarshaled by the
|
|
||||||
// yaml.v2 library. The yaml.v2 package only supports a
|
|
||||||
// subset of primative types.
|
|
||||||
func encode(v interface{}) string {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return v
|
|
||||||
case bool:
|
|
||||||
return strconv.FormatBool(v)
|
|
||||||
case int:
|
|
||||||
return strconv.Itoa(v)
|
|
||||||
case float64:
|
|
||||||
return strconv.FormatFloat(v, 'g', -1, 64)
|
|
||||||
case []byte:
|
|
||||||
return base64.StdEncoding.EncodeToString(v)
|
|
||||||
case []interface{}:
|
|
||||||
return encodeSlice(v)
|
|
||||||
default:
|
|
||||||
return encodeMap(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function encodes a parameter in map format.
|
|
||||||
func encodeMap(v interface{}) string {
|
|
||||||
yml, _ := yaml.Marshal(v)
|
|
||||||
out, _ := json.YAMLToJSON(yml)
|
|
||||||
return string(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function encodes a parameter in slice format.
|
|
||||||
func encodeSlice(v interface{}) string {
|
|
||||||
out, _ := yaml.Marshal(v)
|
|
||||||
|
|
||||||
in := []string{}
|
|
||||||
err := yaml.Unmarshal(out, &in)
|
|
||||||
if err == nil {
|
|
||||||
return strings.Join(in, ",")
|
|
||||||
}
|
|
||||||
out, _ = json.YAMLToJSON(out)
|
|
||||||
return string(out)
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestEncode(t *testing.T) {
|
|
||||||
testdatum := []struct {
|
|
||||||
data interface{}
|
|
||||||
text string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
data: "foo",
|
|
||||||
text: "foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: true,
|
|
||||||
text: "true",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 42,
|
|
||||||
text: "42",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: float64(42.424242),
|
|
||||||
text: "42.424242",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: []interface{}{"foo", "bar", "baz"},
|
|
||||||
text: "foo,bar,baz",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: []interface{}{1, 1, 2, 3, 5, 8},
|
|
||||||
text: "1,1,2,3,5,8",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: []byte("foo"),
|
|
||||||
text: "Zm9v",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: []interface{}{
|
|
||||||
struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}{
|
|
||||||
Name: "john",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
text: `[{"name":"john"}]`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: map[interface{}]interface{}{"foo": "bar"},
|
|
||||||
text: `{"foo":"bar"}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testdata := range testdatum {
|
|
||||||
if got, want := encode(testdata.data), testdata.text; got != want {
|
|
||||||
t.Errorf("Want interface{} encoded to %q, got %q", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package image
|
|
||||||
|
|
||||||
import "github.com/docker/distribution/reference"
|
|
||||||
|
|
||||||
// Trim returns the short image name without tag.
|
|
||||||
func Trim(name string) string {
|
|
||||||
ref, err := reference.ParseAnyReference(name)
|
|
||||||
if err != nil {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
named, err := reference.ParseNamed(ref.String())
|
|
||||||
if err != nil {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
named = reference.TrimNamed(named)
|
|
||||||
return reference.FamiliarName(named)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand returns the fully qualified image name.
|
|
||||||
func Expand(name string) string {
|
|
||||||
ref, err := reference.ParseAnyReference(name)
|
|
||||||
if err != nil {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
named, err := reference.ParseNamed(ref.String())
|
|
||||||
if err != nil {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
named = reference.TagNameOnly(named)
|
|
||||||
return named.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match returns true if the image name matches
|
|
||||||
// an image in the list. Note the image tag is not used
|
|
||||||
// in the matching logic.
|
|
||||||
func Match(from string, to ...string) bool {
|
|
||||||
from = Trim(from)
|
|
||||||
for _, match := range to {
|
|
||||||
if from == Trim(match) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchTag returns true if the image name matches
|
|
||||||
// an image in the list, including the tag.
|
|
||||||
func MatchTag(a, b string) bool {
|
|
||||||
return Expand(a) == Expand(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchHostname returns true if the image hostname
|
|
||||||
// matches the specified hostname.
|
|
||||||
func MatchHostname(image, hostname string) bool {
|
|
||||||
ref, err := reference.ParseAnyReference(image)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
named, err := reference.ParseNamed(ref.String())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if hostname == "index.docker.io" {
|
|
||||||
hostname = "docker.io"
|
|
||||||
}
|
|
||||||
return reference.Domain(named) == hostname
|
|
||||||
}
|
|
@ -1,299 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package image
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func Test_trimImage(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: "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 := Trim(test.from), test.want
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Want image %q trimmed to %q, got %q", test.from, want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_expandImage(t *testing.T) {
|
|
||||||
testdata := []struct {
|
|
||||||
from string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
from: "golang",
|
|
||||||
want: "docker.io/library/golang:latest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "golang:latest",
|
|
||||||
want: "docker.io/library/golang:latest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "golang:1.0.0",
|
|
||||||
want: "docker.io/library/golang:1.0.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "library/golang",
|
|
||||||
want: "docker.io/library/golang:latest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "library/golang:latest",
|
|
||||||
want: "docker.io/library/golang:latest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "library/golang:1.0.0",
|
|
||||||
want: "docker.io/library/golang:1.0.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "index.docker.io/library/golang:1.0.0",
|
|
||||||
want: "docker.io/library/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 := Expand(test.from), test.want
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Want image %q expanded to %q, got %q", test.from, want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_matchImage(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 := Match(test.from, test.to), test.want
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Want image %q matching %q is %v", test.from, test.to, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_matchHostname(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: "golang:latest",
|
|
||||||
hostname: "index.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,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "*&^%",
|
|
||||||
hostname: "1.2.3.4:8000",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_matchTag(t *testing.T) {
|
|
||||||
testdata := []struct {
|
|
||||||
a, b string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
a: "golang:1.0",
|
|
||||||
b: "golang:1.0",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "golang",
|
|
||||||
b: "golang:latest",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "docker.io/library/golang",
|
|
||||||
b: "golang:latest",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "golang",
|
|
||||||
b: "golang:1.0",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "golang:1.0",
|
|
||||||
b: "golang:2.0",
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range testdata {
|
|
||||||
got, want := MatchTag(test.a, test.b), test.want
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Want image %q matching image tag %q is %v", test.a, test.b, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package rand
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
var chars = []byte("abcdefghijklmnopqrstuvwxyz0123456789")
|
|
||||||
|
|
||||||
// random string length
|
|
||||||
const length = 32
|
|
||||||
|
|
||||||
// String returns a string value.
|
|
||||||
func String() string {
|
|
||||||
clen := len(chars)
|
|
||||||
maxrb := 255 - (256 % clen)
|
|
||||||
b := make([]byte, length)
|
|
||||||
r := make([]byte, length+(length/4)) // storage for random bytes.
|
|
||||||
i := 0
|
|
||||||
for {
|
|
||||||
if _, err := rand.Read(r); err != nil {
|
|
||||||
panic("rand: error reading random bytes")
|
|
||||||
}
|
|
||||||
for _, rb := range r {
|
|
||||||
c := int(rb)
|
|
||||||
if c > maxrb {
|
|
||||||
// Skip this number to avoid modulo bias.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
b[i] = chars[c%clen]
|
|
||||||
i++
|
|
||||||
if i == length {
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setupScript(spec *engine.Spec, dst *engine.Step, src *yaml.Container) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, command := range src.Commands {
|
|
||||||
escaped := fmt.Sprintf("%q", command)
|
|
||||||
escaped = strings.Replace(escaped, "$", `\$`, -1)
|
|
||||||
buf.WriteString(fmt.Sprintf(
|
|
||||||
traceScript,
|
|
||||||
escaped,
|
|
||||||
command,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
script := fmt.Sprintf(
|
|
||||||
buildScript,
|
|
||||||
buf.String(),
|
|
||||||
)
|
|
||||||
spec.Files = append(spec.Files, &engine.File{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
Name: src.Name,
|
|
||||||
},
|
|
||||||
Data: []byte(script),
|
|
||||||
})
|
|
||||||
dst.Files = append(dst.Files, &engine.FileMount{
|
|
||||||
Name: src.Name,
|
|
||||||
Path: "/usr/drone/bin/init",
|
|
||||||
Mode: 0777,
|
|
||||||
})
|
|
||||||
|
|
||||||
dst.Docker.Command = []string{"/bin/sh"}
|
|
||||||
dst.Docker.Args = []string{"/usr/drone/bin/init"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildScript is a helper script this is added to the build
|
|
||||||
// to prepare the environment and execute the build commands.
|
|
||||||
const buildScript = `
|
|
||||||
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 DRONE_NETRC_USERNAME
|
|
||||||
unset DRONE_NETRC_PASSWORD
|
|
||||||
set -e
|
|
||||||
%s
|
|
||||||
`
|
|
||||||
|
|
||||||
// traceScript is a helper script that is added to
|
|
||||||
// the build script to trace a command.
|
|
||||||
const traceScript = `
|
|
||||||
echo + %s
|
|
||||||
%s
|
|
||||||
`
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
@ -1,72 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setupScriptWin(spec *engine.Spec, dst *engine.Step, src *yaml.Container) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, command := range src.Commands {
|
|
||||||
escaped := fmt.Sprintf("%q", command)
|
|
||||||
escaped = strings.Replace(escaped, "$", `\$`, -1)
|
|
||||||
buf.WriteString(fmt.Sprintf(
|
|
||||||
traceScriptWin,
|
|
||||||
escaped,
|
|
||||||
command,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
script := fmt.Sprintf(
|
|
||||||
buildScriptWin,
|
|
||||||
buf.String(),
|
|
||||||
)
|
|
||||||
dst.Docker.Command = []string{"powershell", "-noprofile", "-noninteractive", "-command"}
|
|
||||||
dst.Docker.Args = []string{"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Env:CI_SCRIPT)) | iex"}
|
|
||||||
dst.Envs["CI_SCRIPT"] = base64.StdEncoding.EncodeToString([]byte(script))
|
|
||||||
dst.Envs["SHELL"] = "powershell.exe"
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildScriptWin is a helper script this is added to the build
|
|
||||||
// to prepare the environment and execute the build commands.
|
|
||||||
const buildScriptWin = `
|
|
||||||
if ($Env:CI_NETRC_MACHINE) {
|
|
||||||
@"
|
|
||||||
machine $Env:CI_NETRC_MACHINE
|
|
||||||
login $Env:CI_NETRC_USERNAME
|
|
||||||
password $Env:CI_NETRC_PASSWORD
|
|
||||||
"@ > (Join-Path $Env:USERPROFILE '_netrc');
|
|
||||||
}
|
|
||||||
[Environment]::SetEnvironmentVariable("CI_NETRC_USERNAME", $null);
|
|
||||||
[Environment]::SetEnvironmentVariable("CI_NETRC_PASSWORD", $null);
|
|
||||||
[Environment]::SetEnvironmentVariable("DRONE_NETRC_USERNAME", $null);
|
|
||||||
[Environment]::SetEnvironmentVariable("DRONE_NETRC_PASSWORD", $null);
|
|
||||||
[Environment]::SetEnvironmentVariable("CI_SCRIPT", $null);
|
|
||||||
$ErrorActionPreference = 'Stop';
|
|
||||||
%s
|
|
||||||
`
|
|
||||||
|
|
||||||
// traceScriptWin 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}
|
|
||||||
`
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
@ -1,57 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import "github.com/drone/drone-yaml/yaml"
|
|
||||||
|
|
||||||
// SkipData provides build metadata use to determine if a
|
|
||||||
// pipeline step should be skipped.
|
|
||||||
type SkipData struct {
|
|
||||||
Branch string
|
|
||||||
Cron string
|
|
||||||
Event string
|
|
||||||
Instance string
|
|
||||||
Ref string
|
|
||||||
Repo string
|
|
||||||
Target string
|
|
||||||
Action string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SkipFunc returns a function that can be used to skip
|
|
||||||
// individual pipeline steps based on build metadata.
|
|
||||||
func SkipFunc(data SkipData) func(*yaml.Container) bool {
|
|
||||||
return func(container *yaml.Container) bool {
|
|
||||||
switch {
|
|
||||||
case !container.When.Branch.Match(data.Branch):
|
|
||||||
return true
|
|
||||||
case !container.When.Cron.Match(data.Cron):
|
|
||||||
return true
|
|
||||||
case !container.When.Event.Match(data.Event):
|
|
||||||
return true
|
|
||||||
case !container.When.Instance.Match(data.Instance):
|
|
||||||
return true
|
|
||||||
case !container.When.Ref.Match(data.Ref):
|
|
||||||
return true
|
|
||||||
case !container.When.Repo.Match(data.Repo):
|
|
||||||
return true
|
|
||||||
case !container.When.Target.Match(data.Target):
|
|
||||||
return true
|
|
||||||
case !container.When.Action.Match(data.Action):
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSkipFunc(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
data SkipData
|
|
||||||
when yaml.Conditions
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
//
|
|
||||||
// test branch conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Branch: "master"},
|
|
||||||
when: yaml.Conditions{Branch: yaml.Condition{Include: []string{"master"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: SkipData{Branch: "master"},
|
|
||||||
when: yaml.Conditions{Branch: yaml.Condition{Exclude: []string{"master"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test cron conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Cron: "nightly"},
|
|
||||||
when: yaml.Conditions{Cron: yaml.Condition{Include: []string{"nightly"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: SkipData{Cron: "nightly"},
|
|
||||||
when: yaml.Conditions{Cron: yaml.Condition{Exclude: []string{"nightly"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test event conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Event: "push"},
|
|
||||||
when: yaml.Conditions{Event: yaml.Condition{Include: []string{"push"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: SkipData{Event: "push"},
|
|
||||||
when: yaml.Conditions{Event: yaml.Condition{Exclude: []string{"push"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test instance conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Instance: "drone.company.com"},
|
|
||||||
when: yaml.Conditions{Instance: yaml.Condition{Include: []string{"drone.company.com"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: SkipData{Instance: "drone.company.com"},
|
|
||||||
when: yaml.Conditions{Instance: yaml.Condition{Exclude: []string{"drone.company.com"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test ref conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Ref: "refs/heads/master"},
|
|
||||||
when: yaml.Conditions{Ref: yaml.Condition{Include: []string{"refs/heads/*"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: SkipData{Ref: "refs/heads/master"},
|
|
||||||
when: yaml.Conditions{Ref: yaml.Condition{Exclude: []string{"refs/heads/*"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test repo conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Repo: "octocat/hello-world"},
|
|
||||||
when: yaml.Conditions{Repo: yaml.Condition{Include: []string{"octocat/hello-world"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: SkipData{Repo: "octocat/hello-world"},
|
|
||||||
when: yaml.Conditions{Repo: yaml.Condition{Exclude: []string{"octocat/hello-world"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test target conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Target: "prod"},
|
|
||||||
when: yaml.Conditions{Target: yaml.Condition{Include: []string{"prod"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: SkipData{Target: "prod"},
|
|
||||||
when: yaml.Conditions{Target: yaml.Condition{Exclude: []string{"prod"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
//
|
|
||||||
// test action conditions
|
|
||||||
//
|
|
||||||
{
|
|
||||||
data: SkipData{Action: "opened"},
|
|
||||||
when: yaml.Conditions{Action: yaml.Condition{Include: []string{"opened"}}},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: SkipData{Action: "opened"},
|
|
||||||
when: yaml.Conditions{Action: yaml.Condition{Exclude: []string{"opened"}}},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, test := range tests {
|
|
||||||
container := &yaml.Container{When: test.when}
|
|
||||||
got := SkipFunc(test.data)(container)
|
|
||||||
if got != test.want {
|
|
||||||
t.Errorf("Want skip %v at index %d", test.want, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/image"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
func createStep(spec *engine.Spec, src *yaml.Container) *engine.Step {
|
|
||||||
dst := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: src.Name,
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"io.drone.step.name": src.Name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Detach: src.Detach,
|
|
||||||
DependsOn: src.DependsOn,
|
|
||||||
Devices: nil,
|
|
||||||
Docker: &engine.DockerStep{
|
|
||||||
Args: src.Command,
|
|
||||||
Command: src.Entrypoint,
|
|
||||||
DNS: src.DNS,
|
|
||||||
DNSSearch: src.DNSSearch,
|
|
||||||
ExtraHosts: src.ExtraHosts,
|
|
||||||
Image: image.Expand(src.Image),
|
|
||||||
Network: src.Network,
|
|
||||||
Networks: nil, // set in compiler.go
|
|
||||||
Ports: toPorts(src),
|
|
||||||
Privileged: src.Privileged,
|
|
||||||
PullPolicy: toPullPolicy(src),
|
|
||||||
User: src.User,
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
Files: nil, // set below
|
|
||||||
IgnoreErr: toIgnoreErr(src),
|
|
||||||
IgnoreStderr: false,
|
|
||||||
IgnoreStdout: false,
|
|
||||||
Resources: toResources(src),
|
|
||||||
RunPolicy: toRunPolicy(src),
|
|
||||||
Secrets: nil, // set below
|
|
||||||
Volumes: nil, // set below
|
|
||||||
WorkingDir: "", // set in compiler.go
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the user is running a service container with
|
|
||||||
// no custom commands, we should revert back to the
|
|
||||||
// user-defined working directory, which may be empty.
|
|
||||||
if dst.Detach && len(src.Commands) == 0 {
|
|
||||||
dst.WorkingDir = src.WorkingDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// appends the volumes to the container def.
|
|
||||||
for _, vol := range src.Volumes {
|
|
||||||
// the user should never be able to directly
|
|
||||||
// mount the docker socket. This should be
|
|
||||||
// restricted by the linter, but we place this
|
|
||||||
// check here just to be safe.
|
|
||||||
if vol.Name == "_docker_socket" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mount := &engine.VolumeMount{
|
|
||||||
Name: vol.Name,
|
|
||||||
Path: vol.MountPath,
|
|
||||||
}
|
|
||||||
dst.Volumes = append(dst.Volumes, mount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// appends the environment variables to the
|
|
||||||
// container definition.
|
|
||||||
for key, value := range src.Environment {
|
|
||||||
// fix https://github.com/drone/drone-yaml/issues/13
|
|
||||||
if value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if value.Secret != "" {
|
|
||||||
sec := &engine.SecretVar{
|
|
||||||
Name: value.Secret,
|
|
||||||
Env: key,
|
|
||||||
}
|
|
||||||
dst.Secrets = append(dst.Secrets, sec)
|
|
||||||
} else {
|
|
||||||
dst.Envs[key] = value.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// appends the settings variables to the
|
|
||||||
// container definition.
|
|
||||||
for key, value := range src.Settings {
|
|
||||||
// fix https://github.com/drone/drone-yaml/issues/13
|
|
||||||
if value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// all settings are passed to the plugin env
|
|
||||||
// variables, prefixed with PLUGIN_
|
|
||||||
key = "PLUGIN_" + strings.ToUpper(key)
|
|
||||||
|
|
||||||
// if the setting parameter is sources from the
|
|
||||||
// secret we create a secret enviornment variable.
|
|
||||||
if value.Secret != "" {
|
|
||||||
sec := &engine.SecretVar{
|
|
||||||
Name: value.Secret,
|
|
||||||
Env: key,
|
|
||||||
}
|
|
||||||
dst.Secrets = append(dst.Secrets, sec)
|
|
||||||
} else {
|
|
||||||
// else if the setting parameter is opaque
|
|
||||||
// we inject as a string-encoded environment
|
|
||||||
// variable.
|
|
||||||
dst.Envs[key] = encode(value.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the step specifies shell commands we generate a
|
|
||||||
// script. The script is copied to the container at
|
|
||||||
// runtime (or mounted as a config map) and then executed
|
|
||||||
// as the entrypoint.
|
|
||||||
if len(src.Commands) > 0 {
|
|
||||||
switch spec.Platform.OS {
|
|
||||||
case "windows":
|
|
||||||
setupScriptWin(spec, dst, src)
|
|
||||||
default:
|
|
||||||
setupScript(spec, dst, src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
|
|
||||||
func createBuildStep(spec *engine.Spec, src *yaml.Container) *engine.Step {
|
|
||||||
dst := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: src.Name,
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"io.drone.step.name": src.Name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Detach: src.Detach,
|
|
||||||
DependsOn: src.DependsOn,
|
|
||||||
Devices: nil,
|
|
||||||
Docker: &engine.DockerStep{
|
|
||||||
Args: []string{"--build"},
|
|
||||||
DNS: src.DNS,
|
|
||||||
Image: "drone/docker",
|
|
||||||
PullPolicy: engine.PullIfNotExists,
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
IgnoreErr: toIgnoreErr(src),
|
|
||||||
IgnoreStderr: false,
|
|
||||||
IgnoreStdout: false,
|
|
||||||
Resources: toResources(src),
|
|
||||||
RunPolicy: toRunPolicy(src),
|
|
||||||
}
|
|
||||||
|
|
||||||
// if v := src.Build.Args; len(v) > 0 {
|
|
||||||
// dst.Envs["DOCKER_BUILD_ARGS"] = strings.Join(v, ",")
|
|
||||||
// }
|
|
||||||
if v := src.Build.CacheFrom; len(v) > 0 {
|
|
||||||
dst.Envs["DOCKER_BUILD_CACHE_FROM"] = strings.Join(v, ",")
|
|
||||||
}
|
|
||||||
// if len(src.Build.Labels) > 0 {
|
|
||||||
// dst.Envs["DOCKER_BUILD_LABELS"] = strings.Join(v, ",")
|
|
||||||
// }
|
|
||||||
if v := src.Build.Dockerfile; v != "" {
|
|
||||||
dst.Envs["DOCKER_BUILD_DOCKERFILE"] = v
|
|
||||||
|
|
||||||
}
|
|
||||||
if v := src.Build.Context; v != "" {
|
|
||||||
dst.Envs["DOCKER_BUILD_CONTEXT"] = v
|
|
||||||
}
|
|
||||||
if v := src.Build.Image; v != "" {
|
|
||||||
alias := image.Trim(v) + ":" + dst.Metadata.UID
|
|
||||||
dst.Envs["DOCKER_BUILD_IMAGE"] = image.Expand(v)
|
|
||||||
dst.Envs["DOCKER_BUILD_IMAGE_ALIAS"] = image.Expand(alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.Volumes = append(dst.Volumes, &engine.VolumeMount{
|
|
||||||
Name: "_docker_socket",
|
|
||||||
Path: "/var/run/docker.sock",
|
|
||||||
})
|
|
||||||
|
|
||||||
return dst
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// WithAuths is a transform function that adds a set
|
|
||||||
// of global registry credentials to the container.
|
|
||||||
func WithAuths(auths []*engine.DockerAuth) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
spec.Docker.Auths = append(spec.Docker.Auths, auths...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthsFunc is a callback function used to request
|
|
||||||
// registry credentials to pull private images.
|
|
||||||
type AuthsFunc func() []*engine.DockerAuth
|
|
||||||
|
|
||||||
// WithAuthsFunc is a transform function that provides
|
|
||||||
// the sepcification with registry authentication
|
|
||||||
// credentials via a callback function.
|
|
||||||
func WithAuthsFunc(f AuthsFunc) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
auths := f()
|
|
||||||
if len(auths) != 0 {
|
|
||||||
spec.Docker.Auths = append(spec.Docker.Auths, auths...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithAuths(t *testing.T) {
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{},
|
|
||||||
Docker: &engine.DockerConfig{},
|
|
||||||
}
|
|
||||||
auths := []*engine.DockerAuth{
|
|
||||||
{
|
|
||||||
Address: "docker.io",
|
|
||||||
Username: "octocat",
|
|
||||||
Password: "correct-horse-battery-staple",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
WithAuths(auths)(spec)
|
|
||||||
if diff := cmp.Diff(auths, spec.Docker.Auths); diff != "" {
|
|
||||||
t.Errorf("Unexpected auths transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithAuthsFunc(t *testing.T) {
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{},
|
|
||||||
Docker: &engine.DockerConfig{},
|
|
||||||
}
|
|
||||||
auths := []*engine.DockerAuth{
|
|
||||||
{
|
|
||||||
Address: "docker.io",
|
|
||||||
Username: "octocat",
|
|
||||||
Password: "correct-horse-battery-staple",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
fn := func() []*engine.DockerAuth {
|
|
||||||
return auths
|
|
||||||
}
|
|
||||||
WithAuthsFunc(fn)(spec)
|
|
||||||
if diff := cmp.Diff(auths, spec.Docker.Auths); diff != "" {
|
|
||||||
t.Errorf("Unexpected auths transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// Combine is a transform function that combines
|
|
||||||
// one or many transform functions.
|
|
||||||
func Combine(fns ...func(*engine.Spec)) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for _, fn := range fns {
|
|
||||||
fn(spec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCombine(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
Combine(
|
|
||||||
WithEnviron(map[string]string{"GOOS": "linux"}),
|
|
||||||
WithEnviron(map[string]string{"GOARCH": "amd64"}),
|
|
||||||
)(spec)
|
|
||||||
want := map[string]string{
|
|
||||||
"GOOS": "linux",
|
|
||||||
"GOARCH": "amd64",
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(want, step.Envs); diff != "" {
|
|
||||||
t.Errorf("Unexpected transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// WithEnviron is a transform function that adds a set
|
|
||||||
// of environment variables to each container.
|
|
||||||
func WithEnviron(envs map[string]string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for key, value := range envs {
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
step.Envs[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithEnviron(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
envs := map[string]string{
|
|
||||||
"GOOS": "linux",
|
|
||||||
"GOARCH": "amd64",
|
|
||||||
}
|
|
||||||
WithEnviron(envs)(spec)
|
|
||||||
if diff := cmp.Diff(envs, step.Envs); diff != "" {
|
|
||||||
t.Errorf("Unexpected transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// Include is a transform function that limits the
|
|
||||||
// pipeline execution to a whitelist of named steps.
|
|
||||||
func Include(names []string) func(*engine.Spec) {
|
|
||||||
set := map[string]struct{}{}
|
|
||||||
for _, name := range names {
|
|
||||||
set[name] = struct{}{}
|
|
||||||
}
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
if len(names) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
if step.Metadata.Name == "clone" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, ok := set[step.Metadata.Name]
|
|
||||||
if !ok {
|
|
||||||
// if the step is not included in the
|
|
||||||
// whitelist the run policy is set to never.
|
|
||||||
step.RunPolicy = engine.RunNever
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exclude is a transform function that limits the
|
|
||||||
// pipeline execution to a whitelist of named steps.
|
|
||||||
func Exclude(names []string) func(*engine.Spec) {
|
|
||||||
set := map[string]struct{}{}
|
|
||||||
for _, name := range names {
|
|
||||||
set[name] = struct{}{}
|
|
||||||
}
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
if len(names) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
if step.Metadata.Name == "clone" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, ok := set[step.Metadata.Name]
|
|
||||||
if ok {
|
|
||||||
// if the step is included in the blacklist
|
|
||||||
// the run policy is set to never.
|
|
||||||
step.RunPolicy = engine.RunNever
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResumeAt is a transform function that modifies the
|
|
||||||
// exuction to resume at a named step.
|
|
||||||
func ResumeAt(name string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
if name == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
if step.Metadata.Name == name {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if step.Metadata.Name == "clone" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
step.RunPolicy = engine.RunNever
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInclude(t *testing.T) {
|
|
||||||
step1 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "clone"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step2 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "build"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step3 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "test"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step1, step2, step3},
|
|
||||||
}
|
|
||||||
Include([]string{"test"})(spec)
|
|
||||||
if got, want := step1.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step2.RunPolicy, engine.RunNever; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step3.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInclude_Empty(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
Include(nil)(spec)
|
|
||||||
if got, want := step.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExclude(t *testing.T) {
|
|
||||||
step1 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "clone"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step2 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "build"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step3 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "test"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step1, step2, step3},
|
|
||||||
}
|
|
||||||
Exclude([]string{"test"})(spec)
|
|
||||||
if got, want := step1.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step2.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step3.RunPolicy, engine.RunNever; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExclude_Empty(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
Exclude(nil)(spec)
|
|
||||||
if got, want := step.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResumeAt(t *testing.T) {
|
|
||||||
step1 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "clone"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step2 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "build"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
step3 := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{Name: "test"},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step1, step2, step3},
|
|
||||||
}
|
|
||||||
ResumeAt("test")(spec)
|
|
||||||
if got, want := step1.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step2.RunPolicy, engine.RunNever; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step3.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResume_Empty(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
RunPolicy: engine.RunOnSuccess,
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
ResumeAt("")(spec)
|
|
||||||
if got, want := step.RunPolicy, engine.RunOnSuccess; got != want {
|
|
||||||
t.Errorf("Want run policy %s got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// WithLables is a transform function that adds a set
|
|
||||||
// of labels to each resource.
|
|
||||||
func WithLables(labels map[string]string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for k, v := range labels {
|
|
||||||
spec.Metadata.Labels[k] = v
|
|
||||||
}
|
|
||||||
for _, resource := range spec.Docker.Volumes {
|
|
||||||
for k, v := range labels {
|
|
||||||
resource.Metadata.Labels[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, resource := range spec.Steps {
|
|
||||||
for k, v := range labels {
|
|
||||||
resource.Metadata.Labels[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithLabels(t *testing.T) {
|
|
||||||
volume := &engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
Docker: &engine.DockerConfig{
|
|
||||||
Volumes: []*engine.Volume{volume},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
labels := map[string]string{
|
|
||||||
"io.drone.build.number": "1",
|
|
||||||
"io.drone.build.event": "push",
|
|
||||||
}
|
|
||||||
WithLables(labels)(spec)
|
|
||||||
if diff := cmp.Diff(labels, spec.Metadata.Labels); diff != "" {
|
|
||||||
t.Errorf("Unexpected spec labels")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(labels, step.Metadata.Labels); diff != "" {
|
|
||||||
t.Errorf("Unexpected step labels")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(labels, volume.Metadata.Labels); diff != "" {
|
|
||||||
t.Errorf("Unexpected volume labels")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
// Copyright the Drone Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// WithLimits is a transform function that applies
|
|
||||||
// resource limits to the container processes.
|
|
||||||
func WithLimits(memlimit, cpulimit int64) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
// if no limits are defined exit immediately.
|
|
||||||
if memlimit == 0 && cpulimit == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// otherwise apply the resource limits to every
|
|
||||||
// step in the runtime spec.
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
if step.Resources == nil {
|
|
||||||
step.Resources = &engine.Resources{}
|
|
||||||
}
|
|
||||||
if step.Resources.Limits == nil {
|
|
||||||
step.Resources.Limits = &engine.ResourceObject{}
|
|
||||||
}
|
|
||||||
step.Resources.Limits.Memory = memlimit
|
|
||||||
step.Resources.Limits.CPU = cpulimit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
// Copyright the Drone Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithLimits(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerStep{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
WithLimits(1, 2)(spec)
|
|
||||||
if got, want := step.Resources.Limits.Memory, int64(1); got != want {
|
|
||||||
t.Errorf("Want memory limit %v, got %v", want, got)
|
|
||||||
}
|
|
||||||
if got, want := step.Resources.Limits.CPU, int64(2); got != want {
|
|
||||||
t.Errorf("Want cpu limit %v, got %v", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithNoLimits(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerStep{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
WithLimits(0, 0)(spec)
|
|
||||||
if step.Resources != nil {
|
|
||||||
t.Errorf("Expect no limits applied")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
netrcName = ".netrc"
|
|
||||||
netrcPath = "/var/run/drone/.netrc"
|
|
||||||
netrcMode = 0777
|
|
||||||
)
|
|
||||||
|
|
||||||
const disableNetrcMount = true
|
|
||||||
|
|
||||||
// WithNetrc is a helper function that creates a netrc file
|
|
||||||
// and mounts the file to all container steps.
|
|
||||||
func WithNetrc(machine, username, password string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
if username == "" || password == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bradrydzewski) temporarily disable mounting
|
|
||||||
// the netrc file due to issues with kubernetes
|
|
||||||
// compatibility.
|
|
||||||
if disableNetrcMount == false {
|
|
||||||
// Currently file mounts don't seem to work in Windows so environment
|
|
||||||
// variables are used instead
|
|
||||||
// FIXME: https://github.com/drone/drone-yaml/issues/20
|
|
||||||
if spec.Platform.OS != "windows" {
|
|
||||||
netrc := generateNetrc(machine, username, password)
|
|
||||||
spec.Files = append(spec.Files, &engine.File{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: netrcName,
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
},
|
|
||||||
Data: []byte(netrc),
|
|
||||||
})
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
step.Files = append(step.Files, &engine.FileMount{
|
|
||||||
Name: netrcName,
|
|
||||||
Path: netrcPath,
|
|
||||||
Mode: netrcMode,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bradrydzewski) these should only be injected
|
|
||||||
// if the file is not mounted, if OS == Windows.
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
if step.Envs == nil {
|
|
||||||
step.Envs = map[string]string{}
|
|
||||||
}
|
|
||||||
step.Envs["CI_NETRC_MACHINE"] = machine
|
|
||||||
step.Envs["CI_NETRC_USERNAME"] = username
|
|
||||||
step.Envs["CI_NETRC_PASSWORD"] = password
|
|
||||||
|
|
||||||
step.Envs["DRONE_NETRC_MACHINE"] = machine
|
|
||||||
step.Envs["DRONE_NETRC_USERNAME"] = username
|
|
||||||
step.Envs["DRONE_NETRC_PASSWORD"] = password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateNetrc(machine, username, password string) string {
|
|
||||||
return fmt.Sprintf("machine %s login %s password %s",
|
|
||||||
machine, username, password)
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ignoreMetadata = cmpopts.IgnoreFields(
|
|
||||||
engine.Metadata{}, "UID")
|
|
||||||
|
|
||||||
func TestWithNetrc(t *testing.T) {
|
|
||||||
if true {
|
|
||||||
t.Skipf("mounting the netrc is temporarily disabled")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "acdj0yjqv7uh5hidveg0ggr42x8oj67b",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
WithNetrc("@machine", "@username", "@password")(spec)
|
|
||||||
if len(step.Files) == 0 {
|
|
||||||
t.Errorf("File mount not added to step")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(spec.Files) == 0 {
|
|
||||||
t.Errorf("File not declared in spec")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file := &engine.File{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Name: ".netrc",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Data: []byte("machine @machine login @username password @password"),
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(file, spec.Files[0], ignoreMetadata); diff != "" {
|
|
||||||
t.Errorf("Unexpected file declaration")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileMount := &engine.FileMount{Name: ".netrc", Path: "/root/.netrc", Mode: 0600}
|
|
||||||
if diff := cmp.Diff(fileMount, step.Files[0], ignoreMetadata); diff != "" {
|
|
||||||
t.Errorf("Unexpected file mount")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithEmptyNetrc(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
WithNetrc("@machine", "", "")(spec)
|
|
||||||
if len(spec.Files) != 0 {
|
|
||||||
t.Errorf("Unexpected file declaration")
|
|
||||||
}
|
|
||||||
if len(step.Files) != 0 {
|
|
||||||
t.Errorf("Unexpected file mount")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import "github.com/drone/drone-runtime/engine"
|
|
||||||
|
|
||||||
// WithNetworks is a transform function that attaches a
|
|
||||||
// list of user-defined Docker networks to each step.
|
|
||||||
func WithNetworks(networks []string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
step.Docker.Networks = append(
|
|
||||||
step.Docker.Networks, networks...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithNetwork(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerStep{
|
|
||||||
Networks: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
nets := []string{"a", "b"}
|
|
||||||
WithNetworks(nets)(spec)
|
|
||||||
if diff := cmp.Diff(nets, step.Docker.Networks); diff != "" {
|
|
||||||
t.Errorf("Unexpected transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithProxy is a transform function that adds the
|
|
||||||
// http_proxy environment variables to every container.
|
|
||||||
func WithProxy() func(*engine.Spec) {
|
|
||||||
environ := map[string]string{}
|
|
||||||
if value := getenv("no_proxy"); value != "" {
|
|
||||||
environ["no_proxy"] = value
|
|
||||||
environ["NO_PROXY"] = value
|
|
||||||
}
|
|
||||||
if value := getenv("http_proxy"); value != "" {
|
|
||||||
environ["http_proxy"] = value
|
|
||||||
environ["HTTP_PROXY"] = value
|
|
||||||
}
|
|
||||||
if value := getenv("https_proxy"); value != "" {
|
|
||||||
environ["https_proxy"] = value
|
|
||||||
environ["HTTPS_PROXY"] = value
|
|
||||||
}
|
|
||||||
return WithEnviron(environ)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getenv(name string) (value string) {
|
|
||||||
name = strings.ToUpper(name)
|
|
||||||
if value := os.Getenv(name); value != "" {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
name = strings.ToLower(name)
|
|
||||||
if value := os.Getenv(name); value != "" {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithProxy(t *testing.T) {
|
|
||||||
var (
|
|
||||||
noProxy = getenv("no_proxy")
|
|
||||||
httpProxy = getenv("https_proxy")
|
|
||||||
httpsProxy = getenv("https_proxy")
|
|
||||||
)
|
|
||||||
defer func() {
|
|
||||||
os.Setenv("no_proxy", noProxy)
|
|
||||||
os.Setenv("NO_PROXY", noProxy)
|
|
||||||
os.Setenv("http_proxy", httpProxy)
|
|
||||||
os.Setenv("HTTP_PROXY", httpProxy)
|
|
||||||
os.Setenv("HTTPS_PROXY", httpsProxy)
|
|
||||||
os.Setenv("https_proxy", httpsProxy)
|
|
||||||
}()
|
|
||||||
|
|
||||||
testdata := map[string]string{
|
|
||||||
"NO_PROXY": "http://dummy.no.proxy",
|
|
||||||
"http_proxy": "http://dummy.http.proxy",
|
|
||||||
"https_proxy": "http://dummy.https.proxy",
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range testdata {
|
|
||||||
os.Setenv(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
WithProxy()(spec)
|
|
||||||
for k, v := range testdata {
|
|
||||||
step := spec.Steps[0]
|
|
||||||
if step.Envs[k] != v {
|
|
||||||
t.Errorf("Expect proxy varaible %s=%q, got %q", k, v, step.Envs[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithSecrets is a transform function that adds a set
|
|
||||||
// of global secrets to the container.
|
|
||||||
func WithSecrets(secrets map[string]string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for key, value := range secrets {
|
|
||||||
spec.Secrets = append(spec.Secrets,
|
|
||||||
&engine.Secret{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: key,
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
},
|
|
||||||
Data: value,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecretFunc is a callback function used to request
|
|
||||||
// named secret, required by a pipeline step.
|
|
||||||
type SecretFunc func(string) *engine.Secret
|
|
||||||
|
|
||||||
// WithSecretFunc is a transform function that resolves
|
|
||||||
// all named secrets through a callback function, and
|
|
||||||
// adds the secrets to the specification.
|
|
||||||
func WithSecretFunc(f SecretFunc) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
// first we get a unique list of all secrets
|
|
||||||
// used by the specification.
|
|
||||||
set := map[string]struct{}{}
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
// if we know the step is not going to run,
|
|
||||||
// we can ignore any secrets that it requires.
|
|
||||||
if step.RunPolicy == engine.RunNever {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, v := range step.Secrets {
|
|
||||||
set[v.Name] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// next we use the callback function to
|
|
||||||
// get the value for each secret, and append
|
|
||||||
// to the specification.
|
|
||||||
for name := range set {
|
|
||||||
secret := f(name)
|
|
||||||
if secret != nil {
|
|
||||||
secret.Metadata.UID = rand.String()
|
|
||||||
secret.Metadata.Namespace = spec.Metadata.Namespace
|
|
||||||
spec.Secrets = append(spec.Secrets, secret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithSecret(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "acdj0yjqv7uh5hidveg0ggr42x8oj67b",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
secrets := map[string]string{
|
|
||||||
"password": "correct-horse-battery-staple",
|
|
||||||
}
|
|
||||||
WithSecrets(secrets)(spec)
|
|
||||||
|
|
||||||
want := []*engine.Secret{
|
|
||||||
{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Name: "password",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Data: "correct-horse-battery-staple",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(want, spec.Secrets, ignoreMetadata); diff != "" {
|
|
||||||
t.Errorf("Unexpected secret transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithSecretFunc(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Envs: map[string]string{},
|
|
||||||
Secrets: []*engine.SecretVar{
|
|
||||||
{
|
|
||||||
Name: "password",
|
|
||||||
Env: "PASSWORD",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "acdj0yjqv7uh5hidveg0ggr42x8oj67b",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Steps: []*engine.Step{
|
|
||||||
step,
|
|
||||||
// this is a step that requests a secret
|
|
||||||
// but should be skipped.
|
|
||||||
{
|
|
||||||
RunPolicy: engine.RunNever,
|
|
||||||
Secrets: []*engine.SecretVar{
|
|
||||||
{
|
|
||||||
Name: "github_token",
|
|
||||||
Env: "GITHUB_TOKEN",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := func(name string) *engine.Secret {
|
|
||||||
if name == "github_token" {
|
|
||||||
t.Errorf("Requested secret for skipped step")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &engine.Secret{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Name: "password",
|
|
||||||
},
|
|
||||||
Data: "correct-horse-battery-staple",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WithSecretFunc(fn)(spec)
|
|
||||||
|
|
||||||
want := []*engine.Secret{
|
|
||||||
{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
Name: "password",
|
|
||||||
Namespace: "pivqfthg1c9hy83ylht1sxx4nygjc7tk",
|
|
||||||
},
|
|
||||||
Data: "correct-horse-battery-staple",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(want, spec.Secrets, ignoreMetadata); diff != "" {
|
|
||||||
t.Errorf("Unexpected secret transform")
|
|
||||||
t.Log(diff)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithVolumes is a transform function that adds a set
|
|
||||||
// of global volumes to the container.
|
|
||||||
func WithVolumes(volumes map[string]string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
for key, value := range volumes {
|
|
||||||
volume := &engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: rand.String(),
|
|
||||||
Namespace: spec.Metadata.Name,
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
HostPath: &engine.VolumeHostPath{
|
|
||||||
Path: key,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec.Docker.Volumes = append(spec.Docker.Volumes, volume)
|
|
||||||
for _, step := range spec.Steps {
|
|
||||||
mount := &engine.VolumeMount{
|
|
||||||
Name: volume.Metadata.Name,
|
|
||||||
Path: value,
|
|
||||||
}
|
|
||||||
step.Volumes = append(step.Volumes, mount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithVolumeSlice is a transform function that adds a set
|
|
||||||
// of global volumes to the container that are defined in
|
|
||||||
// --volume=host:container format.
|
|
||||||
func WithVolumeSlice(volumes []string) func(*engine.Spec) {
|
|
||||||
to := map[string]string{}
|
|
||||||
for _, s := range volumes {
|
|
||||||
parts := strings.Split(s, ":")
|
|
||||||
if len(parts) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
key := parts[0]
|
|
||||||
val := parts[1]
|
|
||||||
to[key] = val
|
|
||||||
}
|
|
||||||
return WithVolumes(to)
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package transform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithVolumes(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerStep{
|
|
||||||
Networks: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Docker: &engine.DockerConfig{},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
vols := map[string]string{"/path/on/host": "/path/in/container"}
|
|
||||||
WithVolumes(vols)(spec)
|
|
||||||
|
|
||||||
if len(step.Volumes) == 0 {
|
|
||||||
t.Error("Expected volume added to container")
|
|
||||||
}
|
|
||||||
if got, want := step.Volumes[0].Path, "/path/in/container"; got != want {
|
|
||||||
t.Errorf("Want mount path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
if len(spec.Docker.Volumes) == 0 {
|
|
||||||
t.Error("Expected volume added to spec")
|
|
||||||
}
|
|
||||||
if got, want := spec.Docker.Volumes[0].HostPath.Path, "/path/on/host"; got != want {
|
|
||||||
t.Errorf("Want host mount path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithVolumeSlice(t *testing.T) {
|
|
||||||
step := &engine.Step{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: "1",
|
|
||||||
Name: "build",
|
|
||||||
},
|
|
||||||
Docker: &engine.DockerStep{
|
|
||||||
Networks: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
spec := &engine.Spec{
|
|
||||||
Docker: &engine.DockerConfig{},
|
|
||||||
Steps: []*engine.Step{step},
|
|
||||||
}
|
|
||||||
vols := []string{"/path/on/host:/path/in/container"}
|
|
||||||
WithVolumeSlice(vols)(spec)
|
|
||||||
|
|
||||||
if len(step.Volumes) == 0 {
|
|
||||||
t.Error("Expected volume added to container")
|
|
||||||
}
|
|
||||||
if got, want := step.Volumes[0].Path, "/path/in/container"; got != want {
|
|
||||||
t.Errorf("Want mount path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
if len(spec.Docker.Volumes) == 0 {
|
|
||||||
t.Error("Expected volume added to spec")
|
|
||||||
}
|
|
||||||
if got, want := spec.Docker.Volumes[0].HostPath.Path, "/path/on/host"; got != want {
|
|
||||||
t.Errorf("Want host mount path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
unixpath "path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/internal/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
workspacePath = "/drone/src"
|
|
||||||
workspaceName = "workspace"
|
|
||||||
workspaceHostName = "host"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setupWorkingDir(src *yaml.Container, dst *engine.Step, path string) {
|
|
||||||
// if the working directory is already set
|
|
||||||
// do not alter.
|
|
||||||
if dst.WorkingDir != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// if the user is running the container as a
|
|
||||||
// service (detached mode) with no commands, we
|
|
||||||
// should use the default working directory.
|
|
||||||
if dst.Detach && len(src.Commands) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// else set the working directory.
|
|
||||||
dst.WorkingDir = path
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function appends the workspace base and
|
|
||||||
// path to the step's list of environment variables.
|
|
||||||
func setupWorkspaceEnv(step *engine.Step, base, path, full string) {
|
|
||||||
step.Envs["DRONE_WORKSPACE_BASE"] = base
|
|
||||||
step.Envs["DRONE_WORKSPACE_PATH"] = path
|
|
||||||
step.Envs["DRONE_WORKSPACE"] = full
|
|
||||||
step.Envs["CI_WORKSPACE_BASE"] = base
|
|
||||||
step.Envs["CI_WORKSPACE_PATH"] = path
|
|
||||||
step.Envs["CI_WORKSPACE"] = full
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the path to a valid windows
|
|
||||||
// path, including the default C drive.
|
|
||||||
func toWindowsDrive(s string) string {
|
|
||||||
return "c:" + toWindowsPath(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the path to a valid windows
|
|
||||||
// path, replacing backslashes with forward slashes.
|
|
||||||
func toWindowsPath(s string) string {
|
|
||||||
return strings.Replace(s, "/", "\\", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
func createWorkspace(from *yaml.Pipeline) (base, path, full string) {
|
|
||||||
base = from.Workspace.Base
|
|
||||||
path = from.Workspace.Path
|
|
||||||
if base == "" {
|
|
||||||
base = workspacePath
|
|
||||||
}
|
|
||||||
full = unixpath.Join(base, path)
|
|
||||||
|
|
||||||
if from.Platform.OS == "windows" {
|
|
||||||
base = toWindowsDrive(base)
|
|
||||||
path = toWindowsPath(path)
|
|
||||||
full = toWindowsDrive(full)
|
|
||||||
}
|
|
||||||
return base, path, full
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
// CreateWorkspace creates the workspace volume as
|
|
||||||
// an empty directory mount.
|
|
||||||
func CreateWorkspace(spec *engine.Spec) {
|
|
||||||
spec.Docker.Volumes = append(spec.Docker.Volumes,
|
|
||||||
&engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: workspaceName,
|
|
||||||
Namespace: spec.Metadata.Namespace,
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
EmptyDir: &engine.VolumeEmptyDir{},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateHostWorkspace returns a WorkspaceFunc that
|
|
||||||
// mounts a host machine volume as the pipeline
|
|
||||||
// workspace.
|
|
||||||
func CreateHostWorkspace(workdir string) func(*engine.Spec) {
|
|
||||||
return func(spec *engine.Spec) {
|
|
||||||
CreateWorkspace(spec)
|
|
||||||
spec.Docker.Volumes = append(
|
|
||||||
spec.Docker.Volumes,
|
|
||||||
&engine.Volume{
|
|
||||||
Metadata: engine.Metadata{
|
|
||||||
UID: rand.String(),
|
|
||||||
Name: workspaceHostName,
|
|
||||||
},
|
|
||||||
HostPath: &engine.VolumeHostPath{
|
|
||||||
Path: workdir,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
// MountWorkspace is a WorkspaceFunc that mounts the
|
|
||||||
// default workspace volume to the pipeline step.
|
|
||||||
func MountWorkspace(step *engine.Step, base, path, full string) {
|
|
||||||
step.Volumes = append(step.Volumes, &engine.VolumeMount{
|
|
||||||
Name: workspaceName,
|
|
||||||
Path: base,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// MountHostWorkspace is a WorkspaceFunc that mounts
|
|
||||||
// the default workspace and host volume to the pipeline.
|
|
||||||
func MountHostWorkspace(step *engine.Step, base, path, full string) {
|
|
||||||
step.Volumes = append(step.Volumes, &engine.VolumeMount{
|
|
||||||
Name: workspaceHostName,
|
|
||||||
Path: full,
|
|
||||||
})
|
|
||||||
if path != "" {
|
|
||||||
step.Volumes = append(step.Volumes, &engine.VolumeMount{
|
|
||||||
Name: workspaceName,
|
|
||||||
Path: base,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/drone/drone-runtime/engine"
|
|
||||||
"github.com/drone/drone-yaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSetupWorkspace(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
path string
|
|
||||||
src *yaml.Container
|
|
||||||
dst *engine.Step
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
path: "/drone/src",
|
|
||||||
src: &yaml.Container{},
|
|
||||||
dst: &engine.Step{},
|
|
||||||
want: "/drone/src",
|
|
||||||
},
|
|
||||||
// do not override the user-defined working dir.
|
|
||||||
{
|
|
||||||
path: "/drone/src",
|
|
||||||
src: &yaml.Container{},
|
|
||||||
dst: &engine.Step{WorkingDir: "/foo"},
|
|
||||||
want: "/foo",
|
|
||||||
},
|
|
||||||
// do not override the default working directory
|
|
||||||
// for service containers with no commands.
|
|
||||||
{
|
|
||||||
path: "/drone/src",
|
|
||||||
src: &yaml.Container{},
|
|
||||||
dst: &engine.Step{Detach: true},
|
|
||||||
want: "",
|
|
||||||
},
|
|
||||||
// overrides the default working directory
|
|
||||||
// for service containers with commands.
|
|
||||||
{
|
|
||||||
path: "/drone/src",
|
|
||||||
src: &yaml.Container{Commands: []string{"whoami"}},
|
|
||||||
dst: &engine.Step{Detach: true},
|
|
||||||
want: "/drone/src",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
setupWorkingDir(test.src, test.dst, test.path)
|
|
||||||
if got, want := test.dst.WorkingDir, test.want; got != want {
|
|
||||||
t.Errorf("Want working_dir %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToWindows(t *testing.T) {
|
|
||||||
got := toWindowsDrive("/go/src/github.com/octocat/hello-world")
|
|
||||||
want := "c:\\go\\src\\github.com\\octocat\\hello-world"
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("Want windows drive %q, got %q", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateWorkspace(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
from *yaml.Pipeline
|
|
||||||
base string
|
|
||||||
path string
|
|
||||||
full string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
from: &yaml.Pipeline{
|
|
||||||
Workspace: yaml.Workspace{
|
|
||||||
Base: "",
|
|
||||||
Path: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
base: "/drone/src",
|
|
||||||
path: "",
|
|
||||||
full: "/drone/src",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: &yaml.Pipeline{
|
|
||||||
Workspace: yaml.Workspace{
|
|
||||||
Base: "",
|
|
||||||
Path: "",
|
|
||||||
},
|
|
||||||
Platform: yaml.Platform{
|
|
||||||
OS: "windows",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
base: "c:\\drone\\src",
|
|
||||||
path: "",
|
|
||||||
full: "c:\\drone\\src",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: &yaml.Pipeline{
|
|
||||||
Workspace: yaml.Workspace{
|
|
||||||
Base: "/drone",
|
|
||||||
Path: "src",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
base: "/drone",
|
|
||||||
path: "src",
|
|
||||||
full: "/drone/src",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: &yaml.Pipeline{
|
|
||||||
Workspace: yaml.Workspace{
|
|
||||||
Base: "/drone",
|
|
||||||
Path: "src",
|
|
||||||
},
|
|
||||||
Platform: yaml.Platform{
|
|
||||||
OS: "windows",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
base: "c:\\drone",
|
|
||||||
path: "src",
|
|
||||||
full: "c:\\drone\\src",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: &yaml.Pipeline{
|
|
||||||
Workspace: yaml.Workspace{
|
|
||||||
Base: "/foo",
|
|
||||||
Path: "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
base: "/foo",
|
|
||||||
path: "bar",
|
|
||||||
full: "/foo/bar",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
base, path, full := createWorkspace(test.from)
|
|
||||||
if got, want := test.base, base; got != want {
|
|
||||||
t.Errorf("Want workspace base %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := test.path, path; got != want {
|
|
||||||
t.Errorf("Want workspace path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
if got, want := test.full, full; got != want {
|
|
||||||
t.Errorf("Want workspace %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConstraintMatch(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,
|
|
||||||
},
|
|
||||||
// double star
|
|
||||||
{
|
|
||||||
conf: "foo/**",
|
|
||||||
with: "foo/bar/baz/qux",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
conf: "foo/**/qux",
|
|
||||||
with: "foo/bar/baz/qux",
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range testdata {
|
|
||||||
c := parseCondition(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 parseCondition(s string) *Condition {
|
|
||||||
c := &Condition{}
|
|
||||||
yaml.Unmarshal([]byte(s), c)
|
|
||||||
return c
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package bitbucket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Config defines the pipeline configuration.
|
|
||||||
Config struct {
|
|
||||||
// Image specifies the Docker image with
|
|
||||||
// which we run your builds.
|
|
||||||
Image string
|
|
||||||
|
|
||||||
// Clone defines the depth of Git clones
|
|
||||||
// for all pipelines.
|
|
||||||
Clone struct {
|
|
||||||
Depth int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pipeline defines the pipeline configuration
|
|
||||||
// which includes a list of all steps for default,
|
|
||||||
// tag, and branch-specific execution.
|
|
||||||
Pipelines struct {
|
|
||||||
Default Stage
|
|
||||||
Tags map[string]Stage
|
|
||||||
Branches map[string]Stage
|
|
||||||
}
|
|
||||||
|
|
||||||
Definitions struct {
|
|
||||||
Services map[string]*Step
|
|
||||||
Caches map[string]string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage contains a list of steps executed
|
|
||||||
// for a specific branch or tag.
|
|
||||||
Stage struct {
|
|
||||||
Name string
|
|
||||||
Steps []*Step
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step defines a build execution unit.
|
|
||||||
Step struct {
|
|
||||||
// Name of the pipeline step.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Image specifies the Docker image with
|
|
||||||
// which we run your builds.
|
|
||||||
Image string
|
|
||||||
|
|
||||||
// Script contains the list of bash commands
|
|
||||||
// that are executed in sequence.
|
|
||||||
Script []string
|
|
||||||
|
|
||||||
// Variables provides environment variables
|
|
||||||
// passed to the container at runtime.
|
|
||||||
Variables map[string]string
|
|
||||||
|
|
||||||
// Artifacts defines files that are to be
|
|
||||||
// snapshotted and shared with the subsequent
|
|
||||||
// step. This is not used, because Drone uses
|
|
||||||
// a shared volume to share artifacts.
|
|
||||||
Artifacts []string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pipeline returns the pipeline stage that best matches the branch
|
|
||||||
// and ref. If there is no matching pipeline specific to the branch
|
|
||||||
// or tag, the default pipeline is returned.
|
|
||||||
func (c *Config) Pipeline(ref string) Stage {
|
|
||||||
// match pipeline by tag name
|
|
||||||
tag := strings.TrimPrefix(ref, "refs/tags/")
|
|
||||||
for pattern, pipeline := range c.Pipelines.Tags {
|
|
||||||
if ok, _ := path.Match(pattern, tag); ok {
|
|
||||||
return pipeline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// match pipeline by branch name
|
|
||||||
branch := strings.TrimPrefix(ref, "refs/heads/")
|
|
||||||
for pattern, pipeline := range c.Pipelines.Branches {
|
|
||||||
if ok, _ := path.Match(pattern, branch); ok {
|
|
||||||
return pipeline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// use default
|
|
||||||
return c.Pipelines.Default
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalYAML implements custom parsing for the stage section of the yaml
|
|
||||||
// to cleanup the structure a bit.
|
|
||||||
func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
in := []struct {
|
|
||||||
Step *Step
|
|
||||||
}{}
|
|
||||||
err := unmarshal(&in)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, step := range in {
|
|
||||||
s.Steps = append(s.Steps, step.Step)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package bitbucket
|
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package bitbucket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
droneyaml "github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/pretty"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(b []byte, ref string) ([]byte, error) {
|
|
||||||
config := new(Config)
|
|
||||||
err := yaml.Unmarshal(b, config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (bradrydzewski) to correctly choose
|
|
||||||
// the pipeline we need to pass the branch
|
|
||||||
// and ref.
|
|
||||||
stage := config.Pipeline(ref)
|
|
||||||
|
|
||||||
pipeline := &droneyaml.Pipeline{}
|
|
||||||
pipeline.Name = "default"
|
|
||||||
pipeline.Kind = "pipeline"
|
|
||||||
|
|
||||||
//
|
|
||||||
// clone
|
|
||||||
//
|
|
||||||
|
|
||||||
pipeline.Clone.Depth = config.Clone.Depth
|
|
||||||
|
|
||||||
//
|
|
||||||
// steps
|
|
||||||
//
|
|
||||||
|
|
||||||
for i, from := range stage.Steps {
|
|
||||||
to := toContainer(from)
|
|
||||||
// defaults to the global image if the
|
|
||||||
// step does not define an image.
|
|
||||||
if to.Image == "" {
|
|
||||||
to.Image = config.Image
|
|
||||||
}
|
|
||||||
if to.Name == "" {
|
|
||||||
to.Name = fmt.Sprintf("step_%d", i)
|
|
||||||
}
|
|
||||||
pipeline.Steps = append(pipeline.Steps, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// services
|
|
||||||
//
|
|
||||||
|
|
||||||
for name, from := range config.Definitions.Services {
|
|
||||||
to := toContainer(from)
|
|
||||||
to.Name = name
|
|
||||||
pipeline.Services = append(pipeline.Services, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// wrap the pipeline in the manifest
|
|
||||||
//
|
|
||||||
|
|
||||||
manifest := &droneyaml.Manifest{}
|
|
||||||
manifest.Resources = append(manifest.Resources, pipeline)
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
pretty.Print(buf, manifest)
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func toContainer(from *Step) *droneyaml.Container {
|
|
||||||
return &droneyaml.Container{
|
|
||||||
Name: from.Name,
|
|
||||||
Image: from.Image,
|
|
||||||
Commands: from.Script,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package bitbucket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
before, after, ref string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
before: "testdata/sample1.yaml",
|
|
||||||
after: "testdata/sample1.yaml.golden",
|
|
||||||
ref: "refs/heads/master",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/sample2.yaml",
|
|
||||||
after: "testdata/sample2.yaml.golden",
|
|
||||||
ref: "refs/heads/feature/foo",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
a, err := ioutil.ReadFile(test.before)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadFile(test.after)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c, err := Convert([]byte(a), test.ref)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if bytes.Equal(b, c) == false {
|
|
||||||
t.Errorf("Unexpected yaml conversion of %s", test.before)
|
|
||||||
t.Log(string(c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
32
yaml/converter/bitbucket/testdata/sample1.yaml
vendored
32
yaml/converter/bitbucket/testdata/sample1.yaml
vendored
@ -1,32 +0,0 @@
|
|||||||
pipelines:
|
|
||||||
default:
|
|
||||||
- step:
|
|
||||||
name: Build and test
|
|
||||||
image: node:8.5.0
|
|
||||||
caches:
|
|
||||||
- node
|
|
||||||
script:
|
|
||||||
- npm install
|
|
||||||
- npm test
|
|
||||||
- npm build
|
|
||||||
artifacts:
|
|
||||||
- dist/**
|
|
||||||
- step:
|
|
||||||
name: Integration test
|
|
||||||
image: node:8.5.0
|
|
||||||
caches:
|
|
||||||
- node
|
|
||||||
services:
|
|
||||||
- postgres
|
|
||||||
script:
|
|
||||||
- npm run integration-test
|
|
||||||
- step:
|
|
||||||
name: Deploy to beanstalk
|
|
||||||
image: python:3.5.1
|
|
||||||
script:
|
|
||||||
- python deploy-to-beanstalk.py
|
|
||||||
|
|
||||||
definitions:
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:9.6.4
|
|
@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: default
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Build and test
|
|
||||||
image: node:8.5.0
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm test
|
|
||||||
- npm build
|
|
||||||
|
|
||||||
- name: Integration test
|
|
||||||
image: node:8.5.0
|
|
||||||
commands:
|
|
||||||
- npm run integration-test
|
|
||||||
|
|
||||||
- name: Deploy to beanstalk
|
|
||||||
image: python:3.5.1
|
|
||||||
commands:
|
|
||||||
- python deploy-to-beanstalk.py
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: postgres
|
|
||||||
image: postgres:9.6.4
|
|
||||||
|
|
||||||
...
|
|
40
yaml/converter/bitbucket/testdata/sample2.yaml
vendored
40
yaml/converter/bitbucket/testdata/sample2.yaml
vendored
@ -1,40 +0,0 @@
|
|||||||
pipelines:
|
|
||||||
branches:
|
|
||||||
feature/*:
|
|
||||||
- step:
|
|
||||||
name: Test
|
|
||||||
image: node:latest
|
|
||||||
script:
|
|
||||||
- npm install
|
|
||||||
- npm test
|
|
||||||
default:
|
|
||||||
- step:
|
|
||||||
name: Build and test
|
|
||||||
image: node:8.5.0
|
|
||||||
caches:
|
|
||||||
- node
|
|
||||||
script:
|
|
||||||
- npm install
|
|
||||||
- npm test
|
|
||||||
- npm build
|
|
||||||
artifacts:
|
|
||||||
- dist/**
|
|
||||||
- step:
|
|
||||||
name: Integration test
|
|
||||||
image: node:8.5.0
|
|
||||||
caches:
|
|
||||||
- node
|
|
||||||
services:
|
|
||||||
- postgres
|
|
||||||
script:
|
|
||||||
- npm run integration-test
|
|
||||||
- step:
|
|
||||||
name: Deploy to beanstalk
|
|
||||||
image: python:3.5.1
|
|
||||||
script:
|
|
||||||
- python deploy-to-beanstalk.py
|
|
||||||
|
|
||||||
definitions:
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:9.6.4
|
|
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: default
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Test
|
|
||||||
image: node:latest
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm test
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: postgres
|
|
||||||
image: postgres:9.6.4
|
|
||||||
|
|
||||||
...
|
|
@ -1,76 +0,0 @@
|
|||||||
package circleci
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Config defines the pipeline configuration.
|
|
||||||
Config struct {
|
|
||||||
// Version specifies the yaml configuration
|
|
||||||
// file version.
|
|
||||||
Version string
|
|
||||||
|
|
||||||
// Jobs defines a list of pipeline jobs.
|
|
||||||
Jobs []*Job
|
|
||||||
|
|
||||||
// Workflows are used to orchestrate jobs.
|
|
||||||
Workflows struct {
|
|
||||||
Version string
|
|
||||||
List map[string]*Workflow `yaml:",inline"`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workflow ochestrates one or more jobs.
|
|
||||||
Workflow struct {
|
|
||||||
Jobs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Job defines a pipeline job.
|
|
||||||
Job struct {
|
|
||||||
// Name of the stage.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Docker configures a Docker executor.
|
|
||||||
Docker Docker
|
|
||||||
|
|
||||||
// Environment variables passed to the executor.
|
|
||||||
Environment map[string]string
|
|
||||||
|
|
||||||
// Steps configures the Job steps.
|
|
||||||
Steps map[string]Step
|
|
||||||
|
|
||||||
// Branches limits execution by branch.
|
|
||||||
Branches []struct {
|
|
||||||
Only []string
|
|
||||||
Ignore []string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step defines a build execution unit.
|
|
||||||
Step struct {
|
|
||||||
Run Run
|
|
||||||
AddSSHKeys map[string]interface{} `yaml:"add_ssh_keys"`
|
|
||||||
AttachWorkspace map[string]interface{} `yaml:"attach_workspace"`
|
|
||||||
Checkout map[string]interface{} `yaml:"checkout"`
|
|
||||||
Deploy map[string]interface{} `yaml:"deploy"`
|
|
||||||
PersistToWorkspace map[string]interface{} `yaml:"persist_to_workspace"`
|
|
||||||
RestoreCache map[string]interface{} `yaml:"restore_cache"`
|
|
||||||
SaveCache map[string]interface{} `yaml:"save_cache"`
|
|
||||||
SetupRemoteDocker map[string]interface{} `yaml:"setup_remote_docker"`
|
|
||||||
StoreArtifacts map[string]interface{} `yaml:"store_artifacts"`
|
|
||||||
StoreTestResults map[string]interface{} `yaml:"store_test_results"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// // UnmarshalYAML implements custom parsing for the stage section of the yaml
|
|
||||||
// // to cleanup the structure a bit.
|
|
||||||
// func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
// in := []struct {
|
|
||||||
// Step *Step
|
|
||||||
// }{}
|
|
||||||
// err := unmarshal(&in)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// for _, step := range in {
|
|
||||||
// s.Steps = append(s.Steps, step.Step)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
// }
|
|
@ -1,28 +0,0 @@
|
|||||||
package circleci
|
|
||||||
|
|
||||||
// Docker configures a Docker executor.
|
|
||||||
type Docker struct {
|
|
||||||
// Image is the Docker image name.
|
|
||||||
Image string
|
|
||||||
|
|
||||||
// Name is the Docker container hostname.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Entrypoint is the Docker container entrypoint.
|
|
||||||
Entrypoint []string
|
|
||||||
|
|
||||||
// Command is the Docker container command.
|
|
||||||
Command []string
|
|
||||||
|
|
||||||
// User is user that runs the Docker entrypoint.
|
|
||||||
User string
|
|
||||||
|
|
||||||
// Environment variables passed to the container.
|
|
||||||
Environment map[string]string
|
|
||||||
|
|
||||||
// Auth credentials to pull private images.
|
|
||||||
Auth map[string]string
|
|
||||||
|
|
||||||
// Auth credentials to pull private ECR images.
|
|
||||||
AWSAuth map[string]string `yaml:"aws_auth"`
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package circleci
|
|
@ -1,34 +0,0 @@
|
|||||||
package circleci
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// Run defines a command
|
|
||||||
type Run struct {
|
|
||||||
// Name of the command
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Command run in the shell.
|
|
||||||
Command string
|
|
||||||
|
|
||||||
// Shell to use to execute the command.
|
|
||||||
Shell string
|
|
||||||
|
|
||||||
// Workiring Directory in which the command
|
|
||||||
// is run.
|
|
||||||
WorkingDir string `yaml:"working_directory"`
|
|
||||||
|
|
||||||
// Command is run in the background.
|
|
||||||
Background bool `yaml:"background"`
|
|
||||||
|
|
||||||
// Amount of time the command can run with
|
|
||||||
// no output before being canceled.
|
|
||||||
NoOutputTimeout time.Duration `yaml:"no_output_timeout"`
|
|
||||||
|
|
||||||
// Environment variables set when running
|
|
||||||
// the command in the shell.
|
|
||||||
Environment map[string]string
|
|
||||||
|
|
||||||
// Defines when the command should be executed.
|
|
||||||
// Values are always, on_success, and on_fail.
|
|
||||||
When string
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package circleci
|
|
||||||
|
|
||||||
const testRun = `
|
|
||||||
- run:
|
|
||||||
name: test
|
|
||||||
command: go test
|
|
||||||
`
|
|
||||||
|
|
||||||
const testRunShort = `
|
|
||||||
- run: go test
|
|
||||||
`
|
|
22
yaml/converter/circleci/testdata/sample1.yml
vendored
22
yaml/converter/circleci/testdata/sample1.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
version: 2
|
|
||||||
jobs:
|
|
||||||
backend:
|
|
||||||
docker:
|
|
||||||
- image: golang:1.8
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: go build
|
|
||||||
- run: go test
|
|
||||||
frontend:
|
|
||||||
docker:
|
|
||||||
- image: node:latest
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: npm install
|
|
||||||
- run: npm test
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
default:
|
|
||||||
jobs:
|
|
||||||
- backend
|
|
||||||
- frontend
|
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !oss
|
|
||||||
|
|
||||||
package converter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone-yaml/yaml/converter/bitbucket"
|
|
||||||
"github.com/drone/drone-yaml/yaml/converter/gitlab"
|
|
||||||
"github.com/drone/drone-yaml/yaml/converter/legacy"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(d []byte, m Metadata) ([]byte, error) {
|
|
||||||
switch m.Filename {
|
|
||||||
case "bitbucket-pipelines.yml":
|
|
||||||
return bitbucket.Convert(d, m.Ref)
|
|
||||||
case "circle.yml", ".circleci/config.yml":
|
|
||||||
// TODO(bradrydzewski)
|
|
||||||
case ".gitlab-ci.yml":
|
|
||||||
return gitlab.Convert(d)
|
|
||||||
case ".travis.yml":
|
|
||||||
// TODO(bradrydzewski)
|
|
||||||
}
|
|
||||||
// if the filename does not match any external
|
|
||||||
// systems we check to see if the configuration
|
|
||||||
// file is a legacy (pre 1.0) .drone.yml format.
|
|
||||||
if legacy.Match(d) {
|
|
||||||
return legacy.Convert(d, m.URL)
|
|
||||||
}
|
|
||||||
// else return the unmodified configuration
|
|
||||||
// back to the caller.
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertString converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func ConvertString(s string, m Metadata) (string, error) {
|
|
||||||
b, err := Convert([]byte(s), m)
|
|
||||||
return string(b), err
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// +build oss
|
|
||||||
|
|
||||||
package converter
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(d []byte, m Metadata) ([]byte, error) {
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertString converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func ConvertString(s string, m Metadata) (string, error) {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright 2019 Drone IO, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// +build oss
|
|
||||||
|
|
||||||
package converter
|
|
@ -1,7 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !oss
|
|
||||||
|
|
||||||
package converter
|
|
@ -1,129 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package gitlab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone-yaml/yaml/converter/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Config defines the pipeline configuration.
|
|
||||||
Config struct {
|
|
||||||
// Image specifies the Docker image with
|
|
||||||
// which we run your builds.
|
|
||||||
Image Image
|
|
||||||
|
|
||||||
// Stages is used to group steps into stages,
|
|
||||||
// where each stage is executed sequentially.
|
|
||||||
Stages []string
|
|
||||||
|
|
||||||
// Services is used to define a set of services
|
|
||||||
// that should be started and linked to each
|
|
||||||
// step in the pipeline.
|
|
||||||
Services []*Image
|
|
||||||
|
|
||||||
// Variables is used to customize execution,
|
|
||||||
// such as the clone strategy.
|
|
||||||
Variables map[string]string
|
|
||||||
|
|
||||||
// Before contains the list of bash commands
|
|
||||||
// that are executed in sequence before the
|
|
||||||
// first job.
|
|
||||||
Before internal.StringSlice `yaml:"before_script"`
|
|
||||||
|
|
||||||
// After contains the list of bash commands
|
|
||||||
// that are executed in sequence after the
|
|
||||||
// last job.
|
|
||||||
After internal.StringSlice `yaml:"after_script"`
|
|
||||||
|
|
||||||
// Jobs is used to define individual units
|
|
||||||
// of execution that make up a stage.
|
|
||||||
Jobs map[string]*Job `yaml:",inline"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Job defines a build execution unit.
|
|
||||||
Job struct {
|
|
||||||
// Name of the pipeline step.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Stage is the name of the stage.
|
|
||||||
Stage string
|
|
||||||
|
|
||||||
// Image specifies the Docker image with
|
|
||||||
// which we run your builds.
|
|
||||||
Image Image
|
|
||||||
|
|
||||||
// Script contains the list of bash commands
|
|
||||||
// that are executed in sequence.
|
|
||||||
Script internal.StringSlice
|
|
||||||
|
|
||||||
// Before contains the list of bash commands
|
|
||||||
// that are executed in sequence before the
|
|
||||||
// primary script.
|
|
||||||
Before internal.StringSlice `yaml:"before_script"`
|
|
||||||
|
|
||||||
// After contains the list of bash commands
|
|
||||||
// that are executed in sequence after the
|
|
||||||
// primary script.
|
|
||||||
After internal.StringSlice `yaml:"after_script"`
|
|
||||||
|
|
||||||
// Services defines a set of services linked
|
|
||||||
// to the job.
|
|
||||||
Services []*Image
|
|
||||||
|
|
||||||
// Only defines the names of branches and tags
|
|
||||||
// for which the job will run.
|
|
||||||
Only internal.StringSlice
|
|
||||||
|
|
||||||
// Except defines the names of branches and tags
|
|
||||||
// for which the job will not run.
|
|
||||||
Except internal.StringSlice
|
|
||||||
|
|
||||||
// Variables is used to customize execution,
|
|
||||||
// such as the clone strategy.
|
|
||||||
Variables map[string]string
|
|
||||||
|
|
||||||
// Allow job to fail. Failed job doesn’t contribute
|
|
||||||
// to commit status
|
|
||||||
AllowFailure bool
|
|
||||||
|
|
||||||
// Define when to run job. Can be on_success, on_failure,
|
|
||||||
// always or manual
|
|
||||||
When internal.StringSlice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image defines a Docker image.
|
|
||||||
Image struct {
|
|
||||||
Name string
|
|
||||||
Entrypoint []string
|
|
||||||
Command []string
|
|
||||||
Alias string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnmarshalYAML implements custom parsing for an Image.
|
|
||||||
func (i *Image) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var name string
|
|
||||||
err := unmarshal(&name)
|
|
||||||
if err == nil {
|
|
||||||
i.Name = name
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data := struct {
|
|
||||||
Name string
|
|
||||||
Entrypoint internal.StringSlice
|
|
||||||
Command internal.StringSlice
|
|
||||||
Alias string
|
|
||||||
}{}
|
|
||||||
err = unmarshal(&data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i.Name = data.Name
|
|
||||||
i.Entrypoint = data.Entrypoint
|
|
||||||
i.Command = data.Command
|
|
||||||
i.Alias = data.Alias
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package gitlab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
droneyaml "github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/compiler/image"
|
|
||||||
"github.com/drone/drone-yaml/yaml/pretty"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(b []byte) ([]byte, error) {
|
|
||||||
config := new(Config)
|
|
||||||
err := yaml.Unmarshal(b, config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
manifest := &droneyaml.Manifest{}
|
|
||||||
|
|
||||||
// if no stages are defined, we create a single,
|
|
||||||
// default stage that will be used for all jobs.
|
|
||||||
if len(config.Stages) == 0 {
|
|
||||||
for name, job := range config.Jobs {
|
|
||||||
config.Stages = append(config.Stages, name)
|
|
||||||
job.Stage = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new pipeline for each stage.
|
|
||||||
var prevstage string
|
|
||||||
for _, stage := range config.Stages {
|
|
||||||
pipeline := &droneyaml.Pipeline{}
|
|
||||||
pipeline.Name = stage
|
|
||||||
pipeline.Kind = droneyaml.KindPipeline
|
|
||||||
manifest.Resources = append(manifest.Resources, pipeline)
|
|
||||||
for name, job := range config.Jobs {
|
|
||||||
if job.Stage != stage {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cmds := []string(config.Before)
|
|
||||||
cmds = append(cmds, []string(job.Before)...)
|
|
||||||
cmds = append(cmds, []string(job.Script)...)
|
|
||||||
cmds = append(cmds, []string(job.After)...)
|
|
||||||
cmds = append(cmds, []string(config.After)...)
|
|
||||||
|
|
||||||
step := &droneyaml.Container{
|
|
||||||
Name: name,
|
|
||||||
Image: job.Image.Name,
|
|
||||||
Command: job.Image.Command,
|
|
||||||
Entrypoint: job.Image.Entrypoint,
|
|
||||||
Commands: cmds,
|
|
||||||
}
|
|
||||||
|
|
||||||
if job.AllowFailure {
|
|
||||||
step.Failure = "ignore"
|
|
||||||
}
|
|
||||||
|
|
||||||
if step.Image == "" {
|
|
||||||
step.Image = config.Image.Name
|
|
||||||
}
|
|
||||||
// TODO: handle Services
|
|
||||||
// TODO: handle Only
|
|
||||||
// TODO: handle Except
|
|
||||||
// TODO: handle Variables
|
|
||||||
// TODO: handle When
|
|
||||||
|
|
||||||
pipeline.Steps = append(pipeline.Steps, step)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, step := range config.Services {
|
|
||||||
step := &droneyaml.Container{
|
|
||||||
Name: step.Alias,
|
|
||||||
Image: step.Name,
|
|
||||||
Command: step.Command,
|
|
||||||
Entrypoint: step.Entrypoint,
|
|
||||||
}
|
|
||||||
if step.Name == "" {
|
|
||||||
step.Name = serviceSlug(step.Image)
|
|
||||||
}
|
|
||||||
pipeline.Services = append(pipeline.Services, step)
|
|
||||||
}
|
|
||||||
|
|
||||||
if prevstage != "" {
|
|
||||||
pipeline.DependsOn = []string{prevstage}
|
|
||||||
}
|
|
||||||
prevstage = stage
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
pretty.Print(buf, manifest)
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serviceSlug(s string) string {
|
|
||||||
s = image.Trim(s)
|
|
||||||
s = strings.Replace(s, "/", "__", -1)
|
|
||||||
return s
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package gitlab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
before, after, ref string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
before: "testdata/example1.yml",
|
|
||||||
after: "testdata/example1.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/example2.yml",
|
|
||||||
after: "testdata/example2.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/example3.yml",
|
|
||||||
after: "testdata/example3.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/example4.yml",
|
|
||||||
after: "testdata/example4.yml.golden",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
a, err := ioutil.ReadFile(test.before)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadFile(test.after)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c, err := Convert([]byte(a))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Equal(b, c) == false {
|
|
||||||
t.Errorf("Unexpected yaml conversion of %s", test.before)
|
|
||||||
dmp := diffmatchpatch.New()
|
|
||||||
diffs := dmp.DiffMain(string(b), string(c), false)
|
|
||||||
t.Log(dmp.DiffCleanupSemantic(diffs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
11
yaml/converter/gitlab/testdata/example1.yml
vendored
11
yaml/converter/gitlab/testdata/example1.yml
vendored
@ -1,11 +0,0 @@
|
|||||||
image: ruby:2.2
|
|
||||||
|
|
||||||
services:
|
|
||||||
- postgres:9.3
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- bundle install
|
|
||||||
|
|
||||||
test:
|
|
||||||
script:
|
|
||||||
- bundle exec rake spec
|
|
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: test
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- bundle install
|
|
||||||
- bundle exec rake spec
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: postgres
|
|
||||||
image: postgres:9.3
|
|
||||||
|
|
||||||
...
|
|
16
yaml/converter/gitlab/testdata/example2.yml
vendored
16
yaml/converter/gitlab/testdata/example2.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
before_script:
|
|
||||||
- bundle install
|
|
||||||
|
|
||||||
test2.1:
|
|
||||||
image: ruby:2.1
|
|
||||||
services:
|
|
||||||
- postgres:9.3
|
|
||||||
script:
|
|
||||||
- bundle exec rake spec
|
|
||||||
|
|
||||||
test2.2:
|
|
||||||
image: ruby:2.2
|
|
||||||
services:
|
|
||||||
- postgres:9.4
|
|
||||||
script:
|
|
||||||
- bundle exec rake spec
|
|
@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: test2.1
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test2.1
|
|
||||||
image: ruby:2.1
|
|
||||||
commands:
|
|
||||||
- bundle install
|
|
||||||
- bundle exec rake spec
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: test2.2
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test2.2
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- bundle install
|
|
||||||
- bundle exec rake spec
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- test2.1
|
|
||||||
|
|
||||||
...
|
|
16
yaml/converter/gitlab/testdata/example3.yml
vendored
16
yaml/converter/gitlab/testdata/example3.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
image:
|
|
||||||
name: ruby:2.2
|
|
||||||
entrypoint: ["/bin/bash"]
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: my-postgres:9.4
|
|
||||||
alias: db-postgres
|
|
||||||
entrypoint: ["/usr/local/bin/db-postgres"]
|
|
||||||
command: ["start"]
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- bundle install
|
|
||||||
|
|
||||||
test:
|
|
||||||
script:
|
|
||||||
- bundle exec rake spec
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: test
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- bundle install
|
|
||||||
- bundle exec rake spec
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: db-postgres
|
|
||||||
image: my-postgres:9.4
|
|
||||||
entrypoint:
|
|
||||||
- /usr/local/bin/db-postgres
|
|
||||||
command:
|
|
||||||
- start
|
|
||||||
|
|
||||||
...
|
|
22
yaml/converter/gitlab/testdata/example4.yml
vendored
22
yaml/converter/gitlab/testdata/example4.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
stages:
|
|
||||||
- build
|
|
||||||
- test
|
|
||||||
- deploy
|
|
||||||
|
|
||||||
image: ruby:2.2
|
|
||||||
|
|
||||||
job 1:
|
|
||||||
stage: build
|
|
||||||
script: make build dependencies
|
|
||||||
|
|
||||||
job 2:
|
|
||||||
stage: build
|
|
||||||
script: make build artifacts
|
|
||||||
|
|
||||||
job 3:
|
|
||||||
stage: test
|
|
||||||
script: make test
|
|
||||||
|
|
||||||
job 4:
|
|
||||||
stage: deploy
|
|
||||||
script: make deploy
|
|
@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: build
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: job 1
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- make build dependencies
|
|
||||||
|
|
||||||
- name: job 2
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- make build artifacts
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: test
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: job 3
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- make test
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- build
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: deploy
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: job 4
|
|
||||||
image: ruby:2.2
|
|
||||||
commands:
|
|
||||||
- make deploy
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- test
|
|
||||||
|
|
||||||
...
|
|
@ -1,24 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
// StringSlice represents a slice of strings or a string.
|
|
||||||
type StringSlice []string
|
|
||||||
|
|
||||||
// UnmarshalYAML implements the Unmarshaller interface.
|
|
||||||
func (s *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var stringType string
|
|
||||||
if err := unmarshal(&stringType); err == nil {
|
|
||||||
*s = []string{stringType}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var sliceType []string
|
|
||||||
if err := unmarshal(&sliceType); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s = sliceType
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStringSlice(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
yaml string
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
yaml: "hello world",
|
|
||||||
want: []string{"hello world"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "[ hello, world ]",
|
|
||||||
want: []string{"hello", "world"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "42",
|
|
||||||
want: []string{"42"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
var got StringSlice
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal([]byte(test.yaml), &got); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual([]string(got), test.want) {
|
|
||||||
t.Errorf("Got slice %v want %v", got, test.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var got StringSlice
|
|
||||||
if err := yaml.Unmarshal([]byte("{}"), &got); err == nil {
|
|
||||||
t.Errorf("Want error unmarshaling invalid string or slice value.")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package legacy
|
|
||||||
|
|
||||||
import "github.com/drone/drone-yaml/yaml/converter/legacy/internal"
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(d []byte, remote string) ([]byte, error) {
|
|
||||||
return yaml.Convert(d, remote)
|
|
||||||
}
|
|
@ -1,476 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
droneyaml "github.com/drone/drone-yaml/yaml"
|
|
||||||
"github.com/drone/drone-yaml/yaml/converter/legacy/matrix"
|
|
||||||
"github.com/drone/drone-yaml/yaml/pretty"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config provides the high-level configuration.
|
|
||||||
type Config struct {
|
|
||||||
Workspace struct {
|
|
||||||
Base string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
Clone Containers
|
|
||||||
Pipeline Containers
|
|
||||||
Services Containers
|
|
||||||
Branches Constraint
|
|
||||||
Matrix interface{}
|
|
||||||
Secrets map[string]struct {
|
|
||||||
Driver string
|
|
||||||
DriverOpts map[string]string `yaml:"driver_opts"`
|
|
||||||
Path string
|
|
||||||
Vault string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert converts the yaml configuration file from
|
|
||||||
// the legacy format to the 1.0+ format.
|
|
||||||
func Convert(d []byte, remote string) ([]byte, error) {
|
|
||||||
// hack: this is a hack to support teams migrating
|
|
||||||
// from 0.8 to 1.0 that are using yaml merge keys.
|
|
||||||
// it can be removed in a future version.
|
|
||||||
if hasMergeKeys(d) {
|
|
||||||
d, _ = expandMergeKeys(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
from := new(Config)
|
|
||||||
err := yaml.Unmarshal(d, from)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
manifest := &droneyaml.Manifest{}
|
|
||||||
|
|
||||||
pipeline := droneyaml.Pipeline{}
|
|
||||||
pipeline.Name = "default"
|
|
||||||
pipeline.Kind = "pipeline"
|
|
||||||
|
|
||||||
pipeline.Workspace.Base = from.Workspace.Base
|
|
||||||
pipeline.Workspace.Path = from.Workspace.Path
|
|
||||||
if pipeline.Workspace.Path == "." {
|
|
||||||
pipeline.Workspace.Path = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if remote != "" {
|
|
||||||
if pipeline.Workspace.Base == "" {
|
|
||||||
pipeline.Workspace.Base = "/drone"
|
|
||||||
}
|
|
||||||
if pipeline.Workspace.Path == "" {
|
|
||||||
pipeline.Workspace.Path = toWorkspacePath(remote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.Getenv("DRONE_CONVERT_YAML_LEGACY_TO_KUBERNETES") == "true" {
|
|
||||||
pipeline.Type = "kubernetes"
|
|
||||||
|
|
||||||
if from.Workspace.Base != "" && from.Workspace.Path != "" {
|
|
||||||
pipeline.Workspace.Base = ""
|
|
||||||
pipeline.Workspace.Path = filepath.Join(
|
|
||||||
from.Workspace.Base,
|
|
||||||
from.Workspace.Path,
|
|
||||||
)
|
|
||||||
} else if from.Workspace.Base != "" {
|
|
||||||
pipeline.Workspace.Base = ""
|
|
||||||
pipeline.Workspace.Path = filepath.Join(
|
|
||||||
from.Workspace.Base,
|
|
||||||
toWorkspacePath(remote),
|
|
||||||
)
|
|
||||||
} else if from.Workspace.Path != "" {
|
|
||||||
pipeline.Workspace.Base = ""
|
|
||||||
pipeline.Workspace.Path = filepath.Join(
|
|
||||||
"/drone",
|
|
||||||
from.Workspace.Path,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
pipeline.Workspace.Base = ""
|
|
||||||
pipeline.Workspace.Path = filepath.Join(
|
|
||||||
"/drone",
|
|
||||||
toWorkspacePath(remote),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(from.Clone.Containers) != 0 {
|
|
||||||
pipeline.Clone.Disable = true
|
|
||||||
for _, container := range from.Clone.Containers {
|
|
||||||
pipeline.Steps = append(pipeline.Steps,
|
|
||||||
toContainer(container),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if os.Getenv("DRONE_CONVERT_YAML_LEGACY_CLONE") == "true" {
|
|
||||||
pipeline.Clone.Disable = true
|
|
||||||
pipeline.Steps = append(pipeline.Steps, &droneyaml.Container{
|
|
||||||
Name: "clone",
|
|
||||||
Image: "plugins/git",
|
|
||||||
Pull: "if-not-exists",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, container := range from.Services.Containers {
|
|
||||||
pipeline.Services = append(pipeline.Services,
|
|
||||||
toContainer(container),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, container := range from.Pipeline.Containers {
|
|
||||||
pipeline.Steps = append(pipeline.Steps,
|
|
||||||
toContainer(container),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
names := map[string]struct{}{}
|
|
||||||
for i, step := range pipeline.Steps {
|
|
||||||
if _, ok := names[step.Name]; ok {
|
|
||||||
step.Name = fmt.Sprintf("%s_%d", step.Name, i)
|
|
||||||
}
|
|
||||||
names[step.Name] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline.Volumes = toVolumes(from)
|
|
||||||
pipeline.Trigger.Branch.Include = from.Branches.Include
|
|
||||||
pipeline.Trigger.Branch.Exclude = from.Branches.Exclude
|
|
||||||
|
|
||||||
// if the user specifies branch conditions, we need to make
|
|
||||||
// sure they are still able to execute tag events.
|
|
||||||
if len(from.Branches.Include) > 0 && len(from.Branches.Exclude) == 0 {
|
|
||||||
pipeline.Trigger.Branch.Include = nil
|
|
||||||
pipeline.Trigger.Ref.Include = []string{
|
|
||||||
"refs/pull/**", // github
|
|
||||||
"refs/pull-requests/**", // bitbucket
|
|
||||||
"refs/merge-requests/**", // gitlab
|
|
||||||
}
|
|
||||||
for _, branch := range from.Branches.Include {
|
|
||||||
pipeline.Trigger.Ref.Include = append(
|
|
||||||
pipeline.Trigger.Ref.Include,
|
|
||||||
"refs/heads/"+branch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for _, step := range pipeline.Steps {
|
|
||||||
if sliceContains("tag", step.When.Event.Include) {
|
|
||||||
pipeline.Trigger.Ref.Include = append(
|
|
||||||
pipeline.Trigger.Ref.Include,
|
|
||||||
"refs/tags/**",
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// registry credentials need to be emulated in 0.8. The
|
|
||||||
// migration utility automatically creates a secret named
|
|
||||||
// .dockerconfigjson for the registry credentials, which
|
|
||||||
// could be automatically added to the converted
|
|
||||||
// configuration. THIS HAS NOT BEEN THOROUGHLY TESTED.
|
|
||||||
if os.Getenv("DRONE_CONVERT_YAML_DEFAULT_PULL_SECRETS") == "true" {
|
|
||||||
pipeline.PullSecrets = []string{".dockerconfigjson"}
|
|
||||||
}
|
|
||||||
|
|
||||||
if from.Matrix != nil {
|
|
||||||
axes, err := matrix.Parse(d)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for index, environ := range axes {
|
|
||||||
current := pipeline
|
|
||||||
current.Name = fmt.Sprintf("matrix-%d", index+1)
|
|
||||||
|
|
||||||
services := make([]*droneyaml.Container, 0)
|
|
||||||
for _, service := range current.Services {
|
|
||||||
if len(service.When.Matrix) == 0 {
|
|
||||||
services = append(services, service)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for whenKey, whenValue := range service.When.Matrix {
|
|
||||||
for envKey, envValue := range environ {
|
|
||||||
if whenKey == envKey && whenValue == envValue {
|
|
||||||
services = append(services, service)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current.Services = services
|
|
||||||
|
|
||||||
steps := make([]*droneyaml.Container, 0)
|
|
||||||
for _, step := range current.Steps {
|
|
||||||
if len(step.When.Matrix) == 0 {
|
|
||||||
steps = append(steps, step)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for whenKey, whenValue := range step.When.Matrix {
|
|
||||||
for envKey, envValue := range environ {
|
|
||||||
if whenKey == envKey && whenValue == envValue {
|
|
||||||
steps = append(steps, step)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current.Steps = steps
|
|
||||||
|
|
||||||
marshaled, err := yaml.Marshal(¤t)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
transformed := string(marshaled)
|
|
||||||
|
|
||||||
for key, value := range environ {
|
|
||||||
if strings.Contains(value, "\n") {
|
|
||||||
value = fmt.Sprintf("%q", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
transformed = strings.Replace(transformed, fmt.Sprintf("${%s}", key), value, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal([]byte(transformed), ¤t); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
manifest.Resources = append(manifest.Resources, ¤t)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
manifest.Resources = append(manifest.Resources, &pipeline)
|
|
||||||
}
|
|
||||||
|
|
||||||
secrets := toSecrets(from)
|
|
||||||
for _, secret := range secrets {
|
|
||||||
manifest.Resources = append(manifest.Resources, secret)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
pretty.Print(buf, manifest)
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func toContainer(from *Container) *droneyaml.Container {
|
|
||||||
return &droneyaml.Container{
|
|
||||||
Name: from.Name,
|
|
||||||
Image: from.Image,
|
|
||||||
Detach: from.Detached,
|
|
||||||
Command: from.Command,
|
|
||||||
Commands: from.Commands,
|
|
||||||
DNS: from.DNS,
|
|
||||||
DNSSearch: from.DNSSearch,
|
|
||||||
Entrypoint: from.Entrypoint,
|
|
||||||
Environment: toEnvironment(from),
|
|
||||||
ExtraHosts: from.ExtraHosts,
|
|
||||||
Pull: toPullPolicy(from.Pull),
|
|
||||||
Privileged: from.Privileged,
|
|
||||||
Settings: toSettings(from.Vargs),
|
|
||||||
Volumes: toVolumeMounts(from.Volumes),
|
|
||||||
When: toConditions(from.Constraints),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy constraint syntax
|
|
||||||
// to the new condition syntax.
|
|
||||||
func toConditions(from Constraints) droneyaml.Conditions {
|
|
||||||
return droneyaml.Conditions{
|
|
||||||
Ref: droneyaml.Condition{
|
|
||||||
Include: from.Ref.Include,
|
|
||||||
Exclude: from.Ref.Exclude,
|
|
||||||
},
|
|
||||||
Repo: droneyaml.Condition{
|
|
||||||
Include: from.Repo.Include,
|
|
||||||
Exclude: from.Repo.Exclude,
|
|
||||||
},
|
|
||||||
Instance: droneyaml.Condition{
|
|
||||||
Include: from.Instance.Include,
|
|
||||||
Exclude: from.Instance.Exclude,
|
|
||||||
},
|
|
||||||
Target: droneyaml.Condition{
|
|
||||||
Include: from.Environment.Include,
|
|
||||||
Exclude: from.Environment.Exclude,
|
|
||||||
},
|
|
||||||
Event: droneyaml.Condition{
|
|
||||||
Include: toPromote(from.Event.Include),
|
|
||||||
Exclude: toPromote(from.Event.Exclude),
|
|
||||||
},
|
|
||||||
Branch: droneyaml.Condition{
|
|
||||||
Include: from.Branch.Include,
|
|
||||||
Exclude: from.Branch.Exclude,
|
|
||||||
},
|
|
||||||
Status: droneyaml.Condition{
|
|
||||||
Include: from.Status.Include,
|
|
||||||
Exclude: from.Status.Exclude,
|
|
||||||
},
|
|
||||||
Matrix: from.Matrix,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function finds and replaces deployment event status
|
|
||||||
// with promote status
|
|
||||||
func toPromote(events []string) []string {
|
|
||||||
for i, s := range events {
|
|
||||||
switch s {
|
|
||||||
case "deploy", "deployment":
|
|
||||||
events[i] = "promote"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return events
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy environment syntax
|
|
||||||
// to the new environment syntax.
|
|
||||||
func toEnvironment(from *Container) map[string]*droneyaml.Variable {
|
|
||||||
envs := map[string]*droneyaml.Variable{}
|
|
||||||
for key, val := range from.Environment.Map {
|
|
||||||
envs[key] = &droneyaml.Variable{
|
|
||||||
Value: val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, val := range from.Secrets.Secrets {
|
|
||||||
name := strings.ToUpper(val.Target)
|
|
||||||
envs[name] = &droneyaml.Variable{
|
|
||||||
Secret: val.Source,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return envs
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy image pull syntax
|
|
||||||
// to the new pull policy syntax.
|
|
||||||
func toPullPolicy(pull bool) string {
|
|
||||||
switch pull {
|
|
||||||
case true:
|
|
||||||
return "always"
|
|
||||||
default:
|
|
||||||
return "if-not-exists"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy secret syntax to the
|
|
||||||
// new secret variable syntax.
|
|
||||||
func toSecrets(from *Config) []*droneyaml.Secret {
|
|
||||||
var keys []string
|
|
||||||
for key := range from.Secrets {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
var secrets []*droneyaml.Secret
|
|
||||||
for _, key := range keys {
|
|
||||||
val := from.Secrets[key]
|
|
||||||
secret := new(droneyaml.Secret)
|
|
||||||
secret.Name = key
|
|
||||||
secret.Kind = "secret"
|
|
||||||
|
|
||||||
if val.Driver == "vault" {
|
|
||||||
if val.DriverOpts != nil {
|
|
||||||
secret.Get.Path = val.DriverOpts["path"]
|
|
||||||
secret.Get.Name = val.DriverOpts["key"]
|
|
||||||
}
|
|
||||||
} else if val.Path != "" {
|
|
||||||
secret.Get.Path = val.Path
|
|
||||||
} else {
|
|
||||||
secret.Get.Path = val.Vault
|
|
||||||
}
|
|
||||||
secrets = append(secrets, secret)
|
|
||||||
}
|
|
||||||
if len(secrets) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return secrets
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy vargs syntax to the
|
|
||||||
// new environment syntax.
|
|
||||||
func toSettings(from map[string]interface{}) map[string]*droneyaml.Parameter {
|
|
||||||
params := map[string]*droneyaml.Parameter{}
|
|
||||||
for key, val := range from {
|
|
||||||
params[key] = &droneyaml.Parameter{
|
|
||||||
Value: val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy volume syntax
|
|
||||||
// to the new volume mount syntax.
|
|
||||||
func toVolumeMounts(from []*Volume) []*droneyaml.VolumeMount {
|
|
||||||
to := []*droneyaml.VolumeMount{}
|
|
||||||
for _, v := range from {
|
|
||||||
to = append(to, &droneyaml.VolumeMount{
|
|
||||||
Name: fmt.Sprintf("%x", v.Source),
|
|
||||||
MountPath: v.Destination,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function converts the legacy volume syntax
|
|
||||||
// to the new volume mount syntax.
|
|
||||||
func toVolumes(from *Config) []*droneyaml.Volume {
|
|
||||||
set := map[string]struct{}{}
|
|
||||||
to := []*droneyaml.Volume{}
|
|
||||||
|
|
||||||
containers := []*Container{}
|
|
||||||
containers = append(containers, from.Pipeline.Containers...)
|
|
||||||
containers = append(containers, from.Services.Containers...)
|
|
||||||
|
|
||||||
for _, container := range containers {
|
|
||||||
for _, v := range container.Volumes {
|
|
||||||
name := fmt.Sprintf("%x", v.Source)
|
|
||||||
if _, ok := set[name]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
set[name] = struct{}{}
|
|
||||||
to = append(to, &droneyaml.Volume{
|
|
||||||
Name: name,
|
|
||||||
HostPath: &droneyaml.VolumeHostPath{
|
|
||||||
Path: v.Source,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return to
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper fucntion creates the workspace path using the
|
|
||||||
// repsotiory url.
|
|
||||||
func toWorkspacePath(link string) string {
|
|
||||||
parsed, err := url.Parse(link)
|
|
||||||
if err != nil {
|
|
||||||
return "src"
|
|
||||||
}
|
|
||||||
hostname := parsed.Hostname()
|
|
||||||
if hostname == "" {
|
|
||||||
return "src"
|
|
||||||
}
|
|
||||||
path := parsed.Path
|
|
||||||
path = strings.TrimPrefix(path, "/")
|
|
||||||
path = strings.TrimSuffix(path, "/")
|
|
||||||
return "src/" + hostname + "/" + path
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function returns true if the slice the string.
|
|
||||||
func sliceContains(match string, items []string) bool {
|
|
||||||
for _, item := range items {
|
|
||||||
if item == match {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
before, after, url string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
before: "testdata/simple.yml",
|
|
||||||
after: "testdata/simple.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/branches.yml",
|
|
||||||
after: "testdata/branches.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/tags.yml",
|
|
||||||
after: "testdata/tags.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/vault_1.yml",
|
|
||||||
after: "testdata/vault_1.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/vault_2.yml",
|
|
||||||
after: "testdata/vault_2.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/vault_3.yml",
|
|
||||||
after: "testdata/vault_3.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/matrix_1.yml",
|
|
||||||
after: "testdata/matrix_1.yml.golden",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
before: "testdata/matrix_2.yml",
|
|
||||||
after: "testdata/matrix_2.yml.golden",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
a, err := ioutil.ReadFile(test.before)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadFile(test.after)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c, err := Convert(a, test.url)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if bytes.Equal(b, c) == false {
|
|
||||||
t.Errorf("Unexpected yaml conversion of %s", test.before)
|
|
||||||
dmp := diffmatchpatch.New()
|
|
||||||
diffs := dmp.DiffMain(string(b), string(c), false)
|
|
||||||
t.Log(dmp.DiffCleanupSemantic(diffs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWorkspacePath(t *testing.T) {
|
|
||||||
tests := []struct{
|
|
||||||
a string
|
|
||||||
b string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
a: "",
|
|
||||||
b: "src",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "https://github.com/octocat/hello-world",
|
|
||||||
b: "src/github.com/octocat/hello-world",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "https://github.com:80/octocat/hello-world",
|
|
||||||
b: "src/github.com/octocat/hello-world",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: "github.com:80/octocat/hello-world",
|
|
||||||
b: "src",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
if got, want := toWorkspacePath(test.a), test.b; got != want {
|
|
||||||
t.Errorf("Want workspace path %s, got %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Constraints defines a set of runtime constraints.
|
|
||||||
Constraints struct {
|
|
||||||
Ref Constraint
|
|
||||||
Repo Constraint
|
|
||||||
Instance Constraint
|
|
||||||
Environment Constraint
|
|
||||||
Event Constraint
|
|
||||||
Branch Constraint
|
|
||||||
Status Constraint
|
|
||||||
Matrix map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constraint defines a runtime constraint.
|
|
||||||
Constraint struct {
|
|
||||||
Include []string
|
|
||||||
Exclude []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConstraintMap defines a runtime constraint map.
|
|
||||||
ConstraintMap struct {
|
|
||||||
Include map[string]string
|
|
||||||
Exclude map[string]string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnmarshalYAML unmarshals the constraint.
|
|
||||||
func (c *Constraint) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var out1 = struct {
|
|
||||||
Include StringSlice
|
|
||||||
Exclude StringSlice
|
|
||||||
}{}
|
|
||||||
|
|
||||||
var out2 StringSlice
|
|
||||||
|
|
||||||
unmarshal(&out1)
|
|
||||||
unmarshal(&out2)
|
|
||||||
|
|
||||||
c.Exclude = out1.Exclude
|
|
||||||
c.Include = append(
|
|
||||||
out1.Include,
|
|
||||||
out2...,
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalYAML unmarshals the constraint map.
|
|
||||||
func (c *ConstraintMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
out1 := struct {
|
|
||||||
Include map[string]string
|
|
||||||
Exclude map[string]string
|
|
||||||
}{
|
|
||||||
Include: map[string]string{},
|
|
||||||
Exclude: map[string]string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
out2 := map[string]string{}
|
|
||||||
|
|
||||||
unmarshal(&out1)
|
|
||||||
unmarshal(&out2)
|
|
||||||
|
|
||||||
c.Include = out1.Include
|
|
||||||
c.Exclude = out1.Exclude
|
|
||||||
for k, v := range out2 {
|
|
||||||
c.Include[k] = v
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Containers represents an ordered list of containers.
|
|
||||||
Containers struct {
|
|
||||||
Containers []*Container
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container represents a Docker container.
|
|
||||||
Container struct {
|
|
||||||
Command StringSlice `yaml:"command,omitempty"`
|
|
||||||
Commands StringSlice `yaml:"commands,omitempty"`
|
|
||||||
Detached bool `yaml:"detach,omitempty"`
|
|
||||||
Devices []string `yaml:"devices,omitempty"`
|
|
||||||
ErrIgnore bool `yaml:"allow_failure,omitempty"`
|
|
||||||
Tmpfs []string `yaml:"tmpfs,omitempty"`
|
|
||||||
DNS StringSlice `yaml:"dns,omitempty"`
|
|
||||||
DNSSearch StringSlice `yaml:"dns_search,omitempty"`
|
|
||||||
Entrypoint StringSlice `yaml:"entrypoint,omitempty"`
|
|
||||||
Environment SliceMap `yaml:"environment,omitempty"`
|
|
||||||
ExtraHosts []string `yaml:"extra_hosts,omitempty"`
|
|
||||||
Image string `yaml:"image,omitempty"`
|
|
||||||
Name string `yaml:"name,omitempty"`
|
|
||||||
Privileged bool `yaml:"privileged,omitempty"`
|
|
||||||
Pull bool `yaml:"pull,omitempty"`
|
|
||||||
Shell string `yaml:"shell,omitempty"`
|
|
||||||
Volumes []*Volume `yaml:"volumes,omitempty"`
|
|
||||||
Secrets Secrets `yaml:"secrets,omitempty"`
|
|
||||||
Constraints Constraints `yaml:"when,omitempty"`
|
|
||||||
Vargs map[string]interface{} `yaml:",inline"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnmarshalYAML implements the Unmarshaller interface.
|
|
||||||
func (c *Containers) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
slice := yaml.MapSlice{}
|
|
||||||
if err := unmarshal(&slice); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range slice {
|
|
||||||
container := Container{}
|
|
||||||
out, _ := yaml.Marshal(s.Value)
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal(out, &container); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
container.Name = fmt.Sprintf("%v", s.Key)
|
|
||||||
c.Containers = append(c.Containers, &container)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Secrets represents a list of container secrets.
|
|
||||||
Secrets struct {
|
|
||||||
Secrets []*Secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Secret represents a container secret.
|
|
||||||
Secret struct {
|
|
||||||
Source string
|
|
||||||
Target string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// UnmarshalYAML implements the Unmarshaller interface.
|
|
||||||
func (s *Secrets) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var strslice []string
|
|
||||||
err := unmarshal(&strslice)
|
|
||||||
if err == nil {
|
|
||||||
for _, str := range strslice {
|
|
||||||
s.Secrets = append(s.Secrets, &Secret{
|
|
||||||
Source: str,
|
|
||||||
Target: str,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return unmarshal(&s.Secrets)
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
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("got secret %v want %v", got.Secrets, test.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// SliceMap represents a slice or map of key pairs.
|
|
||||||
type SliceMap struct {
|
|
||||||
Map map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalYAML implements custom Yaml unmarshaling.
|
|
||||||
func (s *SliceMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
s.Map = map[string]string{}
|
|
||||||
err := unmarshal(&s.Map)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var slice []string
|
|
||||||
err = unmarshal(&slice)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, v := range slice {
|
|
||||||
parts := strings.SplitN(v, "=", 2)
|
|
||||||
if len(parts) == 2 {
|
|
||||||
key := parts[0]
|
|
||||||
val := parts[1]
|
|
||||||
s.Map[key] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMapSlice(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
yaml string
|
|
||||||
want map[string]string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
yaml: "[ foo=bar, baz=qux ]",
|
|
||||||
want: map[string]string{"foo": "bar", "baz": "qux"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "{ foo: bar, baz: qux }",
|
|
||||||
want: map[string]string{"foo": "bar", "baz": "qux"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
var got SliceMap
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal([]byte(test.yaml), &got); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(got.Map, test.want) {
|
|
||||||
t.Errorf("Got map %v want %v", got, test.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var got SliceMap
|
|
||||||
if err := yaml.Unmarshal([]byte("1"), &got); err == nil {
|
|
||||||
t.Errorf("Want error unmarshaling invalid map value.")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
// StringSlice represents a slice of strings or a string.
|
|
||||||
type StringSlice []string
|
|
||||||
|
|
||||||
// UnmarshalYAML implements the Unmarshaller interface.
|
|
||||||
func (s *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var stringType string
|
|
||||||
if err := unmarshal(&stringType); err == nil {
|
|
||||||
*s = []string{stringType}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var sliceType []string
|
|
||||||
if err := unmarshal(&sliceType); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*s = sliceType
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
||||||
// Use of this source code is governed by the Drone Non-Commercial License
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package yaml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/buildkite/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStringSlice(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
yaml string
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
yaml: "hello world",
|
|
||||||
want: []string{"hello world"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "[ hello, world ]",
|
|
||||||
want: []string{"hello", "world"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
yaml: "42",
|
|
||||||
want: []string{"42"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
var got StringSlice
|
|
||||||
|
|
||||||
if err := yaml.Unmarshal([]byte(test.yaml), &got); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual([]string(got), test.want) {
|
|
||||||
t.Errorf("Got slice %v want %v", got, test.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var got StringSlice
|
|
||||||
if err := yaml.Unmarshal([]byte("{}"), &got); err == nil {
|
|
||||||
t.Errorf("Want error unmarshaling invalid string or slice value.")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
pipeline:
|
|
||||||
greeting:
|
|
||||||
image: alpine
|
|
||||||
commands:
|
|
||||||
- echo hello
|
|
@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: default
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: greeting
|
|
||||||
pull: if-not-exists
|
|
||||||
image: alpine
|
|
||||||
commands:
|
|
||||||
- echo hello
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
ref:
|
|
||||||
- refs/pull/**
|
|
||||||
- refs/pull-requests/**
|
|
||||||
- refs/merge-requests/**
|
|
||||||
- refs/heads/master
|
|
||||||
|
|
||||||
...
|
|
@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
pipeline:
|
|
||||||
test:
|
|
||||||
image: golang:${GO_VERSION}
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
redis:
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- GO_VERSION: 1.11
|
|
||||||
REDIS_VERSION: 2.6
|
|
||||||
- GO_VERSION: 1.10
|
|
||||||
REDIS_VERSION: 2.6
|
|
||||||
- GO_VERSION: 1.9
|
|
||||||
REDIS_VERSION: 2.6
|
|
@ -1,61 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-1
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.11
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-2
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.10
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-3
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.9
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
...
|
|
@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
pipeline:
|
|
||||||
test:
|
|
||||||
image: golang:${GO_VERSION}
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
redis:
|
|
||||||
image: redis:${REDIS_VERSION}
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
GO_VERSION:
|
|
||||||
- 1.11
|
|
||||||
- 1.10
|
|
||||||
|
|
||||||
REDIS_VERSION:
|
|
||||||
- 2.6
|
|
||||||
- 2.8
|
|
@ -1,81 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-1
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.11
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-2
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.11
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.8
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-3
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.10
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.6
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: matrix-4
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:1.10
|
|
||||||
commands:
|
|
||||||
- go test -v ./...
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: redis
|
|
||||||
pull: if-not-exists
|
|
||||||
image: redis:2.8
|
|
||||||
|
|
||||||
...
|
|
@ -1,48 +0,0 @@
|
|||||||
workspace:
|
|
||||||
base: /go
|
|
||||||
path: src/github.com/octocat/hello-world
|
|
||||||
|
|
||||||
pipeline:
|
|
||||||
build:
|
|
||||||
image: golang
|
|
||||||
commands:
|
|
||||||
- go get
|
|
||||||
- go build
|
|
||||||
volumes:
|
|
||||||
- /tmp/go:/go/bin
|
|
||||||
environment:
|
|
||||||
- GOOS=linux
|
|
||||||
- GOARCH=amd64
|
|
||||||
|
|
||||||
test:
|
|
||||||
image: golang:latest
|
|
||||||
volumes:
|
|
||||||
- /tmp/go:/go/bin
|
|
||||||
commands:
|
|
||||||
- go test -v
|
|
||||||
|
|
||||||
docker:
|
|
||||||
image: plugins/docker
|
|
||||||
secrets:
|
|
||||||
- docker_username
|
|
||||||
- docker_password
|
|
||||||
repo: octocat/hello-world
|
|
||||||
when:
|
|
||||||
branch: master
|
|
||||||
|
|
||||||
slack:
|
|
||||||
image: plugins/slack
|
|
||||||
secrets:
|
|
||||||
- source: token
|
|
||||||
target: slack_token
|
|
||||||
channel: general
|
|
||||||
|
|
||||||
services:
|
|
||||||
database:
|
|
||||||
image: mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_USERNAME: foo
|
|
||||||
MYSQL_PASSWORD: bar
|
|
||||||
|
|
||||||
branches:
|
|
||||||
- master
|
|
@ -1,79 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: default
|
|
||||||
|
|
||||||
platform:
|
|
||||||
os: linux
|
|
||||||
arch: amd64
|
|
||||||
|
|
||||||
workspace:
|
|
||||||
base: /go
|
|
||||||
path: src/github.com/octocat/hello-world
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang
|
|
||||||
commands:
|
|
||||||
- go get
|
|
||||||
- go build
|
|
||||||
environment:
|
|
||||||
GOARCH: amd64
|
|
||||||
GOOS: linux
|
|
||||||
volumes:
|
|
||||||
- name: 2f746d702f676f
|
|
||||||
path: /go/bin
|
|
||||||
|
|
||||||
- name: test
|
|
||||||
pull: if-not-exists
|
|
||||||
image: golang:latest
|
|
||||||
commands:
|
|
||||||
- go test -v
|
|
||||||
volumes:
|
|
||||||
- name: 2f746d702f676f
|
|
||||||
path: /go/bin
|
|
||||||
|
|
||||||
- name: docker
|
|
||||||
pull: if-not-exists
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
repo: octocat/hello-world
|
|
||||||
environment:
|
|
||||||
DOCKER_PASSWORD:
|
|
||||||
from_secret: docker_password
|
|
||||||
DOCKER_USERNAME:
|
|
||||||
from_secret: docker_username
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
|
|
||||||
- name: slack
|
|
||||||
pull: if-not-exists
|
|
||||||
image: plugins/slack
|
|
||||||
settings:
|
|
||||||
channel: general
|
|
||||||
environment:
|
|
||||||
SLACK_TOKEN:
|
|
||||||
from_secret: token
|
|
||||||
|
|
||||||
services:
|
|
||||||
- name: database
|
|
||||||
pull: if-not-exists
|
|
||||||
image: mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_PASSWORD: bar
|
|
||||||
MYSQL_USERNAME: foo
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- name: 2f746d702f676f
|
|
||||||
host:
|
|
||||||
path: /tmp/go
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
ref:
|
|
||||||
- refs/pull/**
|
|
||||||
- refs/pull-requests/**
|
|
||||||
- refs/merge-requests/**
|
|
||||||
- refs/heads/master
|
|
||||||
|
|
||||||
...
|
|
10
yaml/converter/legacy/internal/testdata/tags.yml
vendored
10
yaml/converter/legacy/internal/testdata/tags.yml
vendored
@ -1,10 +0,0 @@
|
|||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
pipeline:
|
|
||||||
greeting:
|
|
||||||
image: alpine
|
|
||||||
commands:
|
|
||||||
- echo hello
|
|
||||||
when:
|
|
||||||
event: [ tag, push ]
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user