1
0
mirror of https://github.com/drone/drone-cli.git synced 2024-11-26 06:07:05 +01:00

Merge branch 'master' into secret-info

This commit is contained in:
Tony Li 2020-04-14 17:00:53 -07:00 committed by GitHub
commit 5400456c24
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
820 changed files with 4402 additions and 418591 deletions

@ -6,17 +6,19 @@ set -x
export CGO_ENABLED=0
# compile for all architectures
GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/amd64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=arm64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/arm64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=arm go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/arm/drone github.com/drone/drone-cli/drone
GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/windows/amd64/drone github.com/drone/drone-cli/drone
GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/darwin/amd64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/amd64/drone ./drone
GOOS=linux GOARCH=arm64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/arm64/drone ./drone
GOOS=linux GOARCH=ppc64le go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/ppc64le/drone ./drone
GOOS=linux GOARCH=arm go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/linux/arm/drone ./drone
GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/windows/amd64/drone.exe ./drone
GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=${DRONE_TAG##v}" -o release/darwin/amd64/drone ./drone
# tar binary files prior to upload
tar -cvzf release/drone_linux_amd64.tar.gz -C release/linux/amd64 drone
tar -cvzf release/drone_linux_arm64.tar.gz -C release/linux/arm64 drone
tar -cvzf release/drone_linux_ppc64le.tar.gz -C release/linux/ppc64le drone
tar -cvzf release/drone_linux_arm.tar.gz -C release/linux/arm drone
tar -cvzf release/drone_windows_amd64.tar.gz -C release/windows/amd64 drone
tar -cvzf release/drone_windows_amd64.tar.gz -C release/windows/amd64 drone.exe
tar -cvzf release/drone_darwin_amd64.tar.gz -C release/darwin/amd64 drone
# generate shas for tar files

@ -1,57 +1,88 @@
workspace:
base: /go
path: src/github.com/drone/drone-cli
kind: pipeline
type: docker
name: default
pipeline:
build:
image: golang:1.9
commands: sh .drone.sh
steps:
- name: build
image: golang:1.13
commands:
- sh .drone.sh
publish_latest:
- name: publish_latest
image: plugins/docker
settings:
repo: drone/cli
secrets: [docker_username, docker_password]
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
when:
event: [push, tag]
publish_alpine:
- name: publish_alpine
image: plugins/docker
settings:
repo: drone/cli
secrets: [docker_username, docker_password]
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
auto_tag_suffix: alpine
dockerfile: Dockerfile.alpine
when:
event: [push, tag]
publish_linux_arm:
- name: publish_linux_arm
image: plugins/docker
settings:
repo: drone/cli
secrets: [docker_username, docker_password]
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
auto_tag_suffix: linux-arm
dockerfile: Dockerfile.linux.arm
when:
event: [push, tag]
publish_linux_arm64:
- name: publish_linux_arm64
image: plugins/docker
settings:
repo: drone/cli
secrets: [docker_username, docker_password]
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
auto_tag_suffix: linux-arm64
dockerfile: Dockerfile.linux.arm64
when:
event: [push, tag]
release:
- name: publish_linux_ppc64le
image: plugins/docker
settings:
repo: drone/cli
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
auto_tag_suffix: linux-ppc64le
dockerfile: Dockerfile.linux.ppc64le
when:
event: [push, tag]
- name: release
image: plugins/github-release
settings:
files:
- release/drone_*.tar.gz
- release/drone_checksums.txt
secrets:
- source: github_token
target: github_release_api_key
api_key:
from_secret: github_token
when:
event: tag

1
.gitignore vendored

@ -1,2 +1,3 @@
drone/drone
release
.env

6
Dockerfile.linux.ppc64le Normal file

@ -0,0 +1,6 @@
FROM drone/ca-certs
COPY release/linux/ppc64le/drone /bin/
ENTRYPOINT ["/bin/drone"]

250
Gopkg.lock generated

@ -1,250 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/Microsoft/go-winio"
packages = ["."]
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
version = "v0.4.7"
[[projects]]
name = "github.com/Sirupsen/logrus"
packages = ["."]
revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
version = "v1.0.4"
[[projects]]
branch = "master"
name = "github.com/cncd/pipeline"
packages = [
"pipeline",
"pipeline/backend",
"pipeline/backend/docker",
"pipeline/frontend",
"pipeline/frontend/yaml",
"pipeline/frontend/yaml/compiler",
"pipeline/frontend/yaml/linter",
"pipeline/frontend/yaml/types",
"pipeline/interrupt",
"pipeline/multipart"
]
revision = "3a09486affc9215ba52f55b1f6e10182458d1aba"
[[projects]]
name = "github.com/docker/distribution"
packages = ["reference"]
revision = "7dba427612198a11b161a27f9d40bb2dca1ccd20"
[[projects]]
name = "github.com/docker/docker"
packages = [
"api/types",
"api/types/blkiodev",
"api/types/container",
"api/types/events",
"api/types/filters",
"api/types/mount",
"api/types/network",
"api/types/reference",
"api/types/registry",
"api/types/strslice",
"api/types/swarm",
"api/types/time",
"api/types/versions",
"api/types/volume",
"client",
"pkg/ioutils",
"pkg/longpath",
"pkg/random",
"pkg/stdcopy",
"pkg/stringid",
"pkg/tlsconfig",
"reference"
]
revision = "f645ffca04abf2dd6c89ac9057a1eb7d2b0ac338"
[[projects]]
name = "github.com/docker/go-connections"
packages = [
"nat",
"sockets",
"tlsconfig"
]
revision = "eb315e36415380e7c2fdee175262560ff42359da"
[[projects]]
name = "github.com/docker/go-units"
packages = ["."]
revision = "f2145db703495b2e525c59662db69a7344b00bb8"
[[projects]]
name = "github.com/docker/libcompose"
packages = ["yaml"]
revision = "1c4bd4542afb20db0b51afd71d9ebceaf206e2dd"
[[projects]]
name = "github.com/drone/drone-go"
packages = ["drone"]
revision = "7f20e6c113d3ffa2af80401c4eba7d510c8fd875"
[[projects]]
branch = "master"
name = "github.com/drone/envsubst"
packages = [
".",
"parse"
]
revision = "f4d1a8ef8670afc9eea1fb95ee09a979fd2763a3"
[[projects]]
name = "github.com/fatih/color"
packages = ["."]
revision = "507f6050b8568533fb3f5504de8e5205fa62a114"
version = "v1.6.0"
[[projects]]
branch = "master"
name = "github.com/flynn/go-shlex"
packages = ["."]
revision = "3f9db97f856818214da2e1057f8ad84803971cff"
[[projects]]
name = "github.com/ghodss/yaml"
packages = ["."]
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/google/go-jsonnet"
packages = [
".",
"ast",
"parser"
]
revision = "0274286eef945e5e24be6ebfc13a9deefdd312ee"
source = "https://github.com/drone/go-jsonnet.git"
[[projects]]
branch = "master"
name = "github.com/jackspirou/syscerts"
packages = ["."]
revision = "b68f5469dff16e102bd6a2d5b3e79341c938d736"
[[projects]]
name = "github.com/joho/godotenv"
packages = [
".",
"autoload"
]
revision = "a79fa1e548e2c689c241d10173efd51e5d689d5b"
version = "v1.2.0"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/opencontainers/go-digest"
packages = ["."]
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1"
[[projects]]
branch = "master"
name = "github.com/pkg/browser"
packages = ["."]
revision = "c90ca0c84f15f81c982e32665bffd8d7aac8f097"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/urfave/cli"
packages = ["."]
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
version = "v1.20.0"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "650f4a345ab4e5b245a3034b110ebc7299e68186"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"proxy"
]
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
[[projects]]
branch = "master"
name = "golang.org/x/oauth2"
packages = [
".",
"internal"
]
revision = "543e37812f10c46c622c9575afd7ad22f22a12ba"
[[projects]]
branch = "master"
name = "golang.org/x/sync"
packages = ["errgroup"]
revision = "fd80eb99c8f653c847d294a001bdf2a3a6f768f5"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
[[projects]]
name = "google.golang.org/appengine"
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch"
]
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "3c2492a2f392e0e4d42f2247aca5631e020aed1e2dea238bb56e27739866927a"
solver-name = "gps-cdcl"
solver-version = 1

@ -1,74 +0,0 @@
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
[[constraint]]
name = "github.com/cncd/pipeline"
branch = "master"
[[constraint]]
name = "github.com/drone/drone-go"
revision = "7f20e6c113d3ffa2af80401c4eba7d510c8fd875"
[[constraint]]
branch = "master"
name = "github.com/drone/envsubst"
[[constraint]]
branch = "master"
name = "github.com/jackspirou/syscerts"
[[constraint]]
name = "github.com/joho/godotenv"
version = "1.2.0"
[[constraint]]
branch = "master"
name = "github.com/pkg/browser"
[[constraint]]
name = "github.com/urfave/cli"
version = "1.20.0"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/oauth2"
[[constraint]]
branch = "master"
name = "github.com/google/go-jsonnet"
source = "https://github.com/drone/go-jsonnet.git"
#
# Some project dependencies hale from the dark ages
# of Go dependnecy management and require that we point
# to specific revisions.
#
[[override]]
name = "github.com/docker/docker"
revision = "f645ffca04abf2dd6c89ac9057a1eb7d2b0ac338"
[[override]]
name = "github.com/docker/distribution"
revision = "7dba427612198a11b161a27f9d40bb2dca1ccd20"
[[override]]
name = "github.com/docker/go-connections"
revision = "eb315e36415380e7c2fdee175262560ff42359da"
[[override]]
name = "github.com/docker/go-units"
revision = "f2145db703495b2e525c59662db69a7344b00bb8"
[[override]]
name = "github.com/docker/libcompose"
revision = "1c4bd4542afb20db0b51afd71d9ebceaf206e2dd"
[prune]
go-tests = true
unused-packages = true
non-go = true

@ -1 +1,12 @@
Command line client for the Drone continuous integration server. Please see the official documentation at http://docs.drone.io/cli-installation/
# drone-cli
Command line client for the Drone continuous integration server.
Documentation:<br/>
https://docs.drone.io/cli
Technical Support:<br/>
https://discourse.drone.io
Bug Tracker:<br/>
https://discourse.drone.io/c/bugs

@ -4,9 +4,9 @@ import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var autoscaleVersionCmd = cli.Command{
@ -18,7 +18,6 @@ var autoscaleVersionCmd = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplAutoscaleVersion,
Hidden: true,
},
},
}
@ -34,7 +33,7 @@ func autoscaleVersion(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}

@ -9,14 +9,14 @@ var Command = cli.Command{
Subcommands: []cli.Command{
buildListCmd,
buildLastCmd,
buildLogsCmd,
buildInfoCmd,
buildCreateCmd,
buildStopCmd,
buildStartCmd,
buildApproveCmd,
buildDeclineCmd,
buildPromoteCmd,
buildRollbackCmd,
buildQueueCmd,
buildKillCmd,
buildPsCmd,
},
}

@ -10,8 +10,8 @@ import (
var buildApproveCmd = cli.Command{
Name: "approve",
Usage: "approve a build",
ArgsUsage: "<repo/name> <build>",
Usage: "approve a build stage",
ArgsUsage: "<repo/name> <build> <stage>",
Action: buildApprove,
}
@ -25,13 +25,17 @@ func buildApprove(c *cli.Context) (err error) {
if err != nil {
return err
}
stage, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildApprove(owner, name, number)
err = client.Approve(owner, name, number, stage)
if err != nil {
return err
}

@ -0,0 +1,56 @@
package build
import (
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var buildCreateCmd = cli.Command{
Name: "create",
Usage: "create a build",
ArgsUsage: "<repo/name>",
Action: buildCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "commit",
Usage: "source commit",
},
cli.StringFlag{
Name: "branch",
Usage: "source branch",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
}
func buildCreate(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
build, err := client.BuildCreate(owner, name, c.String("commit"), c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

@ -10,8 +10,8 @@ import (
var buildDeclineCmd = cli.Command{
Name: "decline",
Usage: "decline a build",
ArgsUsage: "<repo/name> <build>",
Usage: "decline a build stage",
ArgsUsage: "<repo/name> <build> <stage>",
Action: buildDecline,
}
@ -25,13 +25,17 @@ func buildDecline(c *cli.Context) (err error) {
if err != nil {
return err
}
stage, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildDecline(owner, name, number)
err = client.Decline(owner, name, number, stage)
if err != nil {
return err
}

@ -6,6 +6,7 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -43,7 +44,7 @@ func buildInfo(c *cli.Context) error {
if err != nil {
return err
}
number = build.Number
number = int(build.Number)
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
@ -56,7 +57,7 @@ func buildInfo(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}
@ -67,9 +68,9 @@ func buildInfo(c *cli.Context) error {
var tmplBuildInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Commit: {{ .After }}
Branch: {{ .Target }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .AuthorEmail }}<{{.AuthorEmail}}>{{ end }}
Message: {{ .Message }}
Author: {{ .Author }}
`

@ -1,42 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildKillCmd = cli.Command{
Name: "kill",
Usage: "force kill a build",
ArgsUsage: "<repo/name> <build>",
Action: buildKill,
Hidden: true,
}
func buildKill(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.BuildKill(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Force killing build %s/%s#%d\n", owner, name, number)
return nil
}

@ -5,6 +5,7 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -44,7 +45,7 @@ func buildLast(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}

@ -5,6 +5,8 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -36,6 +38,11 @@ var buildListCmd = cli.Command{
Usage: "limit the list size",
Value: 25,
},
cli.IntFlag{
Name: "page",
Usage: "page number",
Value: 1,
},
},
}
@ -51,12 +58,12 @@ func buildList(c *cli.Context) error {
return err
}
builds, err := client.BuildList(owner, name)
builds, err := client.BuildList(owner, name, drone.ListOptions{Page: c.Int("page")})
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
@ -71,7 +78,7 @@ func buildList(c *cli.Context) error {
if count >= limit {
break
}
if branch != "" && build.Branch != branch {
if branch != "" && build.Target != branch {
continue
}
if event != "" && build.Event != event {
@ -90,9 +97,9 @@ func buildList(c *cli.Context) error {
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Commit: {{ .After }}
Branch: {{ .Target }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Author: {{ .Author }} {{ if .AuthorEmail }}<{{.AuthorEmail}}>{{ end }}
Message: {{ .Message }}
`

@ -1,18 +0,0 @@
package build
import (
"fmt"
"github.com/urfave/cli"
)
var buildLogsCmd = cli.Command{
Name: "logs",
Usage: "show build logs",
ArgsUsage: "<repo/name> [build] [job]",
Action: buildLogs,
}
func buildLogs(c *cli.Context) error {
return fmt.Errorf("Command temporarily disabled. See https://github.com/drone/drone/issues/2005")
}

@ -0,0 +1,59 @@
package build
import (
"os"
"strconv"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var buildPromoteCmd = cli.Command{
Name: "promote",
Usage: "promote a build",
ArgsUsage: "<repo/name> <build> <environment>",
Action: buildPromote,
Flags: []cli.Flag{
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
}
func buildPromote(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
target := c.Args().Get(2)
params := internal.ParseKeyPair(c.StringSlice("param"))
client, err := internal.NewClient(c)
if err != nil {
return err
}
build, err := client.Promote(owner, name, number, target, params)
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

@ -1,82 +0,0 @@
package build
import (
"os"
"strconv"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildPsCmd = cli.Command{
Name: "ps",
Usage: "show build steps",
ArgsUsage: "<repo/name> [build]",
Action: buildPs,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildPs,
},
},
}
func buildPs(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" || len(buildArg) == 0 {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, proc := range build.Procs {
for _, child := range proc.Children {
if err := tmpl.Execute(os.Stdout, child); err != nil {
return err
}
}
}
return nil
}
// template for build ps information
var tmplBuildPs = "\x1b[33mProc #{{ .PID }} \x1b[0m" + `
Step: {{ .Name }}
State: {{ .State }}
`

@ -1,18 +1,18 @@
package build
import (
"fmt"
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var buildQueueCmd = cli.Command{
Name: "queue",
Usage: "show build queue",
ArgsUsage: " ",
ArgsUsage: "",
Action: buildQueue,
Flags: []cli.Flag{
cli.StringFlag{
@ -20,44 +20,74 @@ var buildQueueCmd = cli.Command{
Usage: "format output",
Value: tmplBuildQueue,
},
cli.StringFlag{
Name: "repo",
Usage: "repo filter",
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
},
},
}
func buildQueue(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
builds, err := client.BuildQueue()
repos, err := client.Incomplete()
if err != nil {
return err
}
if len(builds) == 0 {
fmt.Println("there are no pending or running builds")
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, build := range builds {
tmpl.Execute(os.Stdout, build)
slug := c.String("repo")
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
for _, repo := range repos {
if slug != "" && repo.Slug != slug {
continue
}
if branch != "" && repo.Build.Target != branch {
continue
}
if event != "" && repo.Build.Event != event {
continue
}
if status != "" && repo.Build.Status != status {
continue
}
tmpl.Execute(os.Stdout, repo)
}
return nil
}
// template for build list information
var tmplBuildQueue = "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
// template for build queue information
var tmplBuildQueue = "\x1b[33m{{ .Slug }}#{{ .Build.Number }} \x1b[0m" + `
Name: {{ .Slug }}
Build: {{ .Build.Number }}
Status: {{ .Build.Status }}
Event: {{ .Build.Event }}
Branch: {{ .Build.Target }}
Ref: {{ .Build.Ref }}
Author: {{ .Build.Author }}{{ if .Build.AuthorEmail }} <{{ .Build.AuthorEmail }}>{{ end }}
Created: {{ .Build.Created | time }}
Started: {{ .Build.Started | time }}
Updated: {{ .Build.Updated | time }}
`

@ -0,0 +1,47 @@
package build
import (
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildRollbackCmd = cli.Command{
Name: "rollback",
Usage: "rollback a build",
ArgsUsage: "<repo/name> <build> <environment>",
Action: buildRollback,
Flags: []cli.Flag{
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
func buildRollback(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
target := c.Args().Get(2)
params := internal.ParseKeyPair(c.StringSlice("param"))
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.Rollback(owner, name, number, target, params)
if err != nil {
return err
}
return nil
}

@ -2,16 +2,18 @@ package build
import (
"errors"
"fmt"
"os"
"strconv"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var buildStartCmd = cli.Command{
Name: "start",
Usage: "start a build",
Name: "restart",
Usage: "restart a build",
ArgsUsage: "<repo/name> [build]",
Action: buildStart,
Flags: []cli.Flag{
@ -19,6 +21,11 @@ var buildStartCmd = cli.Command{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
}
@ -42,7 +49,7 @@ func buildStart(c *cli.Context) (err error) {
if err != nil {
return err
}
number = build.Number
number = int(build.Number)
} else {
if len(buildArg) == 0 {
return errors.New("missing job number")
@ -55,11 +62,14 @@ func buildStart(c *cli.Context) (err error) {
params := internal.ParseKeyPair(c.StringSlice("param"))
build, err := client.BuildStart(owner, name, number, params)
build, err := client.BuildRestart(owner, name, number, params)
if err != nil {
return err
}
fmt.Printf("Starting build %s/%s#%d\n", owner, name, build.Number)
return nil
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

@ -11,7 +11,7 @@ import (
var buildStopCmd = cli.Command{
Name: "stop",
Usage: "stop a build",
ArgsUsage: "<repo/name> [build] [job]",
ArgsUsage: "<repo/name> [build]",
Action: buildStop,
}
@ -25,21 +25,17 @@ func buildStop(c *cli.Context) (err error) {
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.BuildStop(owner, name, number, job)
err = client.BuildCancel(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Stopping build %s/%s#%d.%d\n", owner, name, number, job)
fmt.Printf("Stopping build %s/%s#%d\n", owner, name, number)
return nil
}

49
drone/convert/convert.go Normal file

@ -0,0 +1,49 @@
package convert
import (
"bytes"
"io"
"io/ioutil"
"os"
"github.com/drone/drone-yaml/yaml/converter"
"github.com/urfave/cli"
)
// Command exports the convert command.
var Command = cli.Command{
Name: "convert",
Usage: "convert legacy format",
ArgsUsage: "<source>",
Action: convert,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "save",
Usage: "save result to source",
},
},
}
func convert(c *cli.Context) error {
path := c.Args().First()
if path == "" {
path = ".drone.yml"
}
raw, err := ioutil.ReadFile(path)
if err != nil {
return err
}
res, err := converter.Convert(raw, converter.Metadata{Filename: path})
if err != nil {
return err
}
if c.Bool("save") {
return ioutil.WriteFile(path, res, 0644)
}
_, err = io.Copy(os.Stderr, bytes.NewReader(res))
return err
}

16
drone/cron/cron.go Normal file

@ -0,0 +1,16 @@
package cron
import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "cron",
Usage: "manage cron jobs",
Subcommands: []cli.Command{
cronListCmd,
cronInfoCmd,
cronCreateCmd,
cronDisableCmd,
cronEnableCmd,
},
}

44
drone/cron/cron_add.go Normal file

@ -0,0 +1,44 @@
package cron
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var cronCreateCmd = cli.Command{
Name: "add",
Usage: "adds a cronjob",
ArgsUsage: "[repo/name] [cronjob] [cronexpr]",
Action: cronCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
},
}
func cronCreate(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
cron := &drone.Cron{
Name: c.Args().Get(1),
Expr: c.Args().Get(2),
Branch: c.String("branch"),
}
_, err = client.CronCreate(owner, name, cron)
if err != nil {
return err
}
return nil
}

@ -0,0 +1,39 @@
package cron
import (
"errors"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var cronDisableCmd = cli.Command{
Name: "disable",
Usage: "disable cron jobs",
ArgsUsage: "[repo/name] [cronjob]",
Action: cronDisable,
}
func cronDisable(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
cron := c.Args().Get(1)
if cron == "" {
return errors.New("missing cronjob name")
}
disabled := true
in := &drone.CronPatch{
Disabled: &disabled,
}
_, err = client.CronUpdate(owner, name, cron, in)
return err
}

39
drone/cron/cron_enable.go Normal file

@ -0,0 +1,39 @@
package cron
import (
"errors"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var cronEnableCmd = cli.Command{
Name: "enable",
Usage: "enable cron jobs",
ArgsUsage: "[repo/name] [cronjob]",
Action: cronEnable,
}
func cronEnable(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
cron := c.Args().Get(1)
if cron == "" {
return errors.New("missing cronjob name")
}
disabled := false
in := &drone.CronPatch{
Disabled: &disabled,
}
_, err = client.CronUpdate(owner, name, cron, in)
return err
}

47
drone/cron/cron_info.go Normal file

@ -0,0 +1,47 @@
package cron
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var cronInfoCmd = cli.Command{
Name: "info",
Usage: "display cron info",
ArgsUsage: "[repo/name]",
Action: cronInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplCronList,
},
},
}
func cronInfo(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
cronjob := c.Args().Get(1)
cron, err := client.Cron(owner, name, cronjob)
if err != nil {
return err
}
format := c.String("format")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, cron)
}

59
drone/cron/cron_list.go Normal file

@ -0,0 +1,59 @@
package cron
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var cronListCmd = cli.Command{
Name: "ls",
Usage: "list cron jobs",
ArgsUsage: "[repo/name]",
Action: cronList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplCronList,
Hidden: true,
},
},
}
func cronList(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
list, err := client.CronList(owner, name)
if err != nil {
return err
}
format := c.String("format") + "\n"
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, cron := range list {
tmpl.Execute(os.Stdout, cron)
}
return nil
}
// template for build list information
var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + `
Expr: {{ .Expr }}
Next: {{ .Next | time }}
{{- if .Disabled }}
Disabled: true
{{- end }}
`

@ -1,125 +0,0 @@
package deploy
import (
"fmt"
"html/template"
"os"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
// Command exports the deploy command.
var Command = cli.Command{
Name: "deploy",
Usage: "deploy code",
ArgsUsage: "<repo/name> <build> <environment>",
Action: deploy,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplDeployInfo,
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
Value: "master",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
Value: drone.EventPush,
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
Value: drone.StatusSuccess,
},
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
func deploy(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" {
// Fetch the build number from the last build
builds, berr := client.BuildList(owner, name)
if berr != nil {
return berr
}
for _, build := range builds {
if branch != "" && build.Branch != branch {
continue
}
if event != "" && build.Event != event {
continue
}
if status != "" && build.Status != status {
continue
}
if build.Number > number {
number = build.Number
}
}
if number == 0 {
return fmt.Errorf("Cannot deploy failure build")
}
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
env := c.Args().Get(2)
if env == "" {
return fmt.Errorf("Please specify the target environment (ie production)")
}
params := internal.ParseKeyPair(c.StringSlice("param"))
deploy, err := client.Deploy(owner, name, number, env, params)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, deploy)
}
// template for deployment information
var tmplDeployInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
Target: {{ .Deploy }}
`

65
drone/encrypt/encrypt.go Normal file

@ -0,0 +1,65 @@
package encrypt
import (
"fmt"
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
// Command is an encryption cli.Command
var Command = cli.Command{
Name: "encrypt",
Usage: "encrypt a secret",
ArgsUsage: "<repo/name> <string>",
Action: encryptSecret,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "allow-pull-request",
Usage: "permit read access to pull requests",
},
cli.BoolFlag{
Name: "allow-push-on-pull-request",
Usage: "permit write access to pull requests (e.g. allow docker push)",
},
},
}
func encryptSecret(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
plaintext := c.Args().Get(1)
if strings.HasPrefix(plaintext, "@") {
path := strings.TrimPrefix(plaintext, "@")
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
plaintext = string(data)
}
secret := &drone.Secret{
Data: plaintext,
PullRequest: c.Bool("allow-pull-request"),
PullRequestPush: c.Bool("allow-push-on-pull-request"),
}
encrypted, err := client.Encrypt(owner, name, secret)
if err != nil {
return err
}
fmt.Println(encrypted)
return nil
}

77
drone/encrypt/registry.go Normal file

@ -0,0 +1,77 @@
package encrypt
// import (
// "fmt"
// "io/ioutil"
// "strings"
// "github.com/drone/drone-cli/drone/internal"
// "github.com/drone/drone-go/drone"
// "github.com/urfave/cli"
// )
// var encryptRegistryCommand = cli.Command{
// Name: "registry",
// Usage: "encrypt registry credentials",
// ArgsUsage: "<repo/name> <string>",
// Action: encryptRegistry,
// Flags: []cli.Flag{
// cli.StringFlag{
// Name: "username",
// Usage: "registry username",
// },
// cli.StringFlag{
// Name: "password",
// Usage: "registry password",
// },
// cli.StringFlag{
// Name: "server",
// Usage: "registry server",
// Value: "docker.io",
// },
// },
// }
// func encryptRegistry(c *cli.Context) error {
// repo := c.Args().First()
// owner, name, err := internal.ParseRepo(repo)
// if err != nil {
// return err
// }
// client, err := internal.NewClient(c)
// if err != nil {
// return err
// }
// password := c.String("password")
// if strings.HasPrefix(password, "@") {
// data, err := ioutil.ReadFile(password)
// if err != nil {
// return err
// }
// password = string(data)
// }
// policy := "pull"
// switch {
// case c.Bool("push"):
// policy = "push"
// case c.Bool("push-pull-request"):
// policy = "push-pull-request"
// }
// registry := &drone.Registry{
// Address: c.String("server"),
// Username: c.String("username"),
// Password: password,
// Policy: policy,
// }
// encrypted, err := client.EncryptRegistry(owner, name, registry)
// if err != nil {
// return err
// }
// fmt.Println(encrypted)
// return nil
// }

493
drone/exec/_backup/exec.go Normal file

@ -0,0 +1,493 @@
package exec
import (
"context"
"io"
"log"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/cncd/pipeline/pipeline"
"github.com/cncd/pipeline/pipeline/backend"
"github.com/cncd/pipeline/pipeline/backend/docker"
"github.com/cncd/pipeline/pipeline/frontend"
"github.com/cncd/pipeline/pipeline/frontend/yaml"
"github.com/cncd/pipeline/pipeline/frontend/yaml/compiler"
"github.com/cncd/pipeline/pipeline/frontend/yaml/linter"
"github.com/cncd/pipeline/pipeline/interrupt"
"github.com/cncd/pipeline/pipeline/multipart"
"github.com/drone/envsubst"
"github.com/urfave/cli"
)
// Command exports the exec command.
var Command = cli.Command{
Name: "exec",
Usage: "execute a local build",
ArgsUsage: "[path/to/.drone.yml]",
Action: func(c *cli.Context) {
if err := exec(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.BoolTFlag{
Name: "local",
Usage: "build from local directory",
EnvVar: "DRONE_LOCAL",
},
cli.DurationFlag{
Name: "timeout",
Usage: "build timeout",
Value: time.Hour,
EnvVar: "DRONE_TIMEOUT",
},
cli.StringSliceFlag{
Name: "volumes",
Usage: "build volumes",
EnvVar: "DRONE_VOLUMES",
},
cli.StringSliceFlag{
Name: "network",
Usage: "external networks",
EnvVar: "DRONE_NETWORKS",
},
cli.StringFlag{
Name: "prefix",
Value: "drone",
Usage: "prefix containers created by drone",
EnvVar: "DRONE_DOCKER_PREFIX",
Hidden: true,
},
cli.StringSliceFlag{
Name: "privileged",
Usage: "privileged plugins",
Value: &cli.StringSlice{
"plugins/docker",
"plugins/acr",
"plugins/ecr",
"plugins/gcr",
"plugins/heroku",
},
},
//
// workspace default
//
cli.StringFlag{
Name: "workspace-base",
Value: "/drone",
EnvVar: "DRONE_WORKSPACE_BASE",
},
cli.StringFlag{
Name: "workspace-path",
Value: "src",
EnvVar: "DRONE_WORKSPACE_PATH",
},
//
// netrc parameters
//
cli.StringFlag{
Name: "netrc-username",
EnvVar: "DRONE_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc-password",
EnvVar: "DRONE_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "netrc-machine",
EnvVar: "DRONE_NETRC_MACHINE",
},
//
// metadata parameters
//
cli.StringFlag{
Name: "system-arch",
Value: "linux/amd64",
EnvVar: "DRONE_SYSTEM_ARCH",
},
cli.StringFlag{
Name: "system-name",
Value: "pipec",
EnvVar: "DRONE_SYSTEM_NAME",
},
cli.StringFlag{
Name: "system-link",
Value: "https://github.com/cncd/pipec",
EnvVar: "DRONE_SYSTEM_LINK",
},
cli.StringFlag{
Name: "repo-name",
EnvVar: "DRONE_REPO_NAME",
},
cli.StringFlag{
Name: "repo-link",
EnvVar: "DRONE_REPO_LINK",
},
cli.StringFlag{
Name: "repo-remote-url",
EnvVar: "DRONE_REPO_REMOTE",
},
cli.StringFlag{
Name: "repo-private",
EnvVar: "DRONE_REPO_PRIVATE",
},
cli.IntFlag{
Name: "build-number",
EnvVar: "DRONE_BUILD_NUMBER",
},
cli.IntFlag{
Name: "parent-build-number",
EnvVar: "DRONE_PARENT_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "build-created",
EnvVar: "DRONE_BUILD_CREATED",
},
cli.Int64Flag{
Name: "build-started",
EnvVar: "DRONE_BUILD_STARTED",
},
cli.Int64Flag{
Name: "build-finished",
EnvVar: "DRONE_BUILD_FINISHED",
},
cli.StringFlag{
Name: "build-status",
EnvVar: "DRONE_BUILD_STATUS",
},
cli.StringFlag{
Name: "build-event",
EnvVar: "DRONE_BUILD_EVENT",
},
cli.StringFlag{
Name: "build-link",
EnvVar: "DRONE_BUILD_LINK",
},
cli.StringFlag{
Name: "build-target",
EnvVar: "DRONE_BUILD_TARGET",
},
cli.StringFlag{
Name: "commit-sha",
EnvVar: "DRONE_COMMIT_SHA",
},
cli.StringFlag{
Name: "commit-ref",
EnvVar: "DRONE_COMMIT_REF",
},
cli.StringFlag{
Name: "commit-refspec",
EnvVar: "DRONE_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "commit-branch",
EnvVar: "DRONE_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit-message",
EnvVar: "DRONE_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "commit-author-name",
EnvVar: "DRONE_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "commit-author-avatar",
EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "commit-author-email",
EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "prev-build-number",
EnvVar: "DRONE_PREV_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "prev-build-created",
EnvVar: "DRONE_PREV_BUILD_CREATED",
},
cli.Int64Flag{
Name: "prev-build-started",
EnvVar: "DRONE_PREV_BUILD_STARTED",
},
cli.Int64Flag{
Name: "prev-build-finished",
EnvVar: "DRONE_PREV_BUILD_FINISHED",
},
cli.StringFlag{
Name: "prev-build-status",
EnvVar: "DRONE_PREV_BUILD_STATUS",
},
cli.StringFlag{
Name: "prev-build-event",
EnvVar: "DRONE_PREV_BUILD_EVENT",
},
cli.StringFlag{
Name: "prev-build-link",
EnvVar: "DRONE_PREV_BUILD_LINK",
},
cli.StringFlag{
Name: "prev-commit-sha",
EnvVar: "DRONE_PREV_COMMIT_SHA",
},
cli.StringFlag{
Name: "prev-commit-ref",
EnvVar: "DRONE_PREV_COMMIT_REF",
},
cli.StringFlag{
Name: "prev-commit-refspec",
EnvVar: "DRONE_PREV_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "prev-commit-branch",
EnvVar: "DRONE_PREV_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "prev-commit-message",
EnvVar: "DRONE_PREV_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "prev-commit-author-name",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "prev-commit-author-avatar",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "prev-commit-author-email",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "job-number",
EnvVar: "DRONE_JOB_NUMBER",
},
cli.StringSliceFlag{
Name: "env, e",
EnvVar: "DRONE_ENV",
},
},
}
func exec(c *cli.Context) error {
file := c.Args().First()
if file == "" {
file = ".drone.yml"
}
metadata := metadataFromContext(c)
environ := metadata.Environ()
secrets := []compiler.Secret{}
for k, v := range metadata.EnvironDrone() {
environ[k] = v
}
for key, val := range metadata.Job.Matrix {
environ[key] = val
secrets = append(secrets, compiler.Secret{
Name: key,
Value: val,
})
}
droneEnv := make(map[string]string)
for _, env := range c.StringSlice("env") {
envs := strings.SplitN(env, "=", 2)
droneEnv[envs[0]] = envs[1]
}
tmpl, err := envsubst.ParseFile(file)
if err != nil {
return err
}
confstr, err := tmpl.Execute(func(name string) string {
return environ[name]
})
if err != nil {
return err
}
conf, err := yaml.ParseString(confstr)
if err != nil {
return err
}
// configure volumes for local execution
volumes := c.StringSlice("volumes")
if c.Bool("local") {
var (
workspaceBase = conf.Workspace.Base
workspacePath = conf.Workspace.Path
)
if workspaceBase == "" {
workspaceBase = c.String("workspace-base")
}
if workspacePath == "" {
workspacePath = c.String("workspace-path")
}
dir, _ := filepath.Abs(filepath.Dir(file))
if runtime.GOOS == "windows" {
dir = convertPathForWindows(dir)
}
volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase)
volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
}
// lint the yaml file
if lerr := linter.New(linter.WithTrusted(true)).Lint(conf); lerr != nil {
return lerr
}
// compiles the yaml file
compiled := compiler.New(
compiler.WithEscalated(
c.StringSlice("privileged")...,
),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
c.String("workspace-base"),
c.String("workspace-path"),
),
compiler.WithNetworks(
c.StringSlice("network")...,
),
compiler.WithPrefix(
c.String("prefix"),
),
compiler.WithProxy(),
compiler.WithLocal(
c.Bool("local"),
),
compiler.WithNetrc(
c.String("netrc-username"),
c.String("netrc-password"),
c.String("netrc-machine"),
),
compiler.WithMetadata(metadata),
compiler.WithSecret(secrets...),
compiler.WithEnviron(droneEnv),
).Compile(conf)
engine, err := docker.NewEnv()
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
defer cancel()
ctx = interrupt.WithContext(ctx)
return pipeline.New(compiled,
pipeline.WithContext(ctx),
pipeline.WithTracer(pipeline.DefaultTracer),
pipeline.WithLogger(defaultLogger),
pipeline.WithEngine(engine),
).Run()
}
// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
return frontend.Metadata{
Repo: frontend.Repo{
Name: c.String("repo-name"),
Link: c.String("repo-link"),
Remote: c.String("repo-remote-url"),
Private: c.Bool("repo-private"),
},
Curr: frontend.Build{
Number: c.Int("build-number"),
Parent: c.Int("parent-build-number"),
Created: c.Int64("build-created"),
Started: c.Int64("build-started"),
Finished: c.Int64("build-finished"),
Status: c.String("build-status"),
Event: c.String("build-event"),
Link: c.String("build-link"),
Target: c.String("build-target"),
Commit: frontend.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
Refspec: c.String("commit-refspec"),
Branch: c.String("commit-branch"),
Message: c.String("commit-message"),
Author: frontend.Author{
Name: c.String("commit-author-name"),
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
},
},
Prev: frontend.Build{
Number: c.Int("prev-build-number"),
Created: c.Int64("prev-build-created"),
Started: c.Int64("prev-build-started"),
Finished: c.Int64("prev-build-finished"),
Status: c.String("prev-build-status"),
Event: c.String("prev-build-event"),
Link: c.String("prev-build-link"),
Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),
Refspec: c.String("prev-commit-refspec"),
Branch: c.String("prev-commit-branch"),
Message: c.String("prev-commit-message"),
Author: frontend.Author{
Name: c.String("prev-commit-author-name"),
Email: c.String("prev-commit-author-email"),
Avatar: c.String("prev-commit-author-avatar"),
},
},
},
Job: frontend.Job{
Number: c.Int("job-number"),
Matrix: availableEnvironment(),
},
Sys: frontend.System{
Name: c.String("system-name"),
Link: c.String("system-link"),
Arch: c.String("system-arch"),
},
}
}
func availableEnvironment() map[string]string {
result := make(map[string]string, 0)
for _, env := range os.Environ() {
pair := strings.SplitN(env, "=", 2)
result[pair[0]] = pair[1]
}
return result
}
func convertPathForWindows(path string) string {
base := filepath.VolumeName(path)
if len(base) == 2 {
path = strings.TrimPrefix(path, base)
base = strings.ToLower(strings.TrimSuffix(base, ":"))
return "/" + base + filepath.ToSlash(path)
}
return filepath.ToSlash(path)
}
var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
part, err := rc.NextPart()
if err != nil {
return err
}
logstream := NewLineWriter(proc.Alias)
io.Copy(logstream, part)
return nil
})

73
drone/exec/env.go Normal file

@ -0,0 +1,73 @@
package exec
import (
"os"
"strings"
"github.com/urfave/cli"
)
func getEnv(c *cli.Context) map[string]string {
env := prefixedEnviron(
os.Environ(),
)
if c.IsSet("branch") {
v := c.String("branch")
env["DRONE_BRANCH"] = v
env["DRONE_COMMIT_BRANCH"] = v
env["DRONE_TARGET_BRANCH"] = v
}
if c.IsSet("event") {
v := c.String("event")
env["DRONE_EVENT"] = v
}
if c.IsSet("instance") {
v := c.String("instance")
env["DRONE_SYSTEM_HOST"] = v
env["DRONE_SYSTEM_HOSTNAME"] = v
}
if c.IsSet("ref") {
v := c.String("ref")
env["DRONE_COMMIT_REF"] = v
}
if c.IsSet("repo") {
v := c.String("repo")
env["DRONE_REPO"] = v
}
if c.IsSet("deploy-to") {
v := c.String("deploy-to")
env["DRONE_DEPLOY_TO"] = v
}
return env
}
// helper function returns all environment variables
// prefixed with DRONE_.
func prefixedEnviron(environ []string) map[string]string {
envs := map[string]string{}
for _, env := range environ {
if !strings.HasPrefix(env, "DRONE_") {
continue
}
parts := strings.SplitN(env, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
val := parts[1]
envs[key] = val
}
return envs
}
// helper function combines one or more maps of environment
// variables into a single map.
func combineEnviron(env ...map[string]string) map[string]string {
c := map[string]string{}
for _, e := range env {
for k, v := range e {
c[k] = v
}
}
return c
}

@ -2,29 +2,35 @@ package exec
import (
"context"
"io"
"errors"
"io/ioutil"
"log"
"net/url"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"strconv"
"time"
"github.com/cncd/pipeline/pipeline"
"github.com/cncd/pipeline/pipeline/backend"
"github.com/cncd/pipeline/pipeline/backend/docker"
"github.com/cncd/pipeline/pipeline/frontend"
"github.com/cncd/pipeline/pipeline/frontend/yaml"
"github.com/cncd/pipeline/pipeline/frontend/yaml/compiler"
"github.com/cncd/pipeline/pipeline/frontend/yaml/linter"
"github.com/cncd/pipeline/pipeline/interrupt"
"github.com/cncd/pipeline/pipeline/multipart"
"github.com/drone/envsubst"
"github.com/drone/drone-runtime/engine"
"github.com/drone/drone-runtime/engine/docker"
"github.com/drone/drone-runtime/runtime"
"github.com/drone/drone-runtime/runtime/term"
"github.com/drone/drone-yaml/yaml"
"github.com/drone/drone-yaml/yaml/compiler"
"github.com/drone/drone-yaml/yaml/compiler/transform"
"github.com/drone/drone-yaml/yaml/converter"
"github.com/drone/drone-yaml/yaml/linter"
"github.com/drone/signal"
"github.com/joho/godotenv"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"github.com/urfave/cli"
)
var tty = isatty.IsTerminal(os.Stdout.Fd())
// Command exports the exec command.
var Command = cli.Command{
Name: "exec",
@ -36,247 +42,107 @@ var Command = cli.Command{
}
},
Flags: []cli.Flag{
cli.BoolTFlag{
Name: "local",
Usage: "build from local directory",
EnvVar: "DRONE_LOCAL",
cli.StringFlag{
Name: "pipeline",
Usage: "Name of the pipeline to execute",
},
cli.StringSliceFlag{
Name: "include",
Usage: "Name of steps to include",
},
cli.StringSliceFlag{
Name: "exclude",
Usage: "Name of steps to exclude",
},
cli.StringFlag{
Name: "resume-at",
Usage: "Name of start to resume at",
},
cli.BoolFlag{
Name: "clone",
Usage: "enable the clone step",
},
cli.BoolFlag{
Name: "trusted",
Usage: "build is trusted",
},
cli.DurationFlag{
Name: "timeout",
Usage: "build timeout",
Value: time.Hour,
EnvVar: "DRONE_TIMEOUT",
},
cli.StringSliceFlag{
Name: "volumes",
Name: "volume",
Usage: "build volumes",
EnvVar: "DRONE_VOLUMES",
},
cli.StringSliceFlag{
Name: "network",
Usage: "external networks",
EnvVar: "DRONE_NETWORKS",
},
cli.StringSliceFlag{
Name: "registry",
Usage: "registry",
},
cli.StringFlag{
Name: "prefix",
Value: "drone",
Usage: "prefix containers created by drone",
EnvVar: "DRONE_DOCKER_PREFIX",
Hidden: true,
Name: "secret-file",
Usage: "secret file, define values that can be used with from_secret",
},
cli.StringFlag{
Name: "env-file",
Usage: "env file",
},
cli.StringSliceFlag{
Name: "privileged",
Usage: "privileged plugins",
Value: &cli.StringSlice{
"plugins/docker",
"plugins/gcr",
"plugins/acr",
"plugins/ecr",
"plugins/gcr",
"plugins/heroku",
},
},
//
// Please note the below flags are mirrored in the pipec and
// should be kept synchronized. Do not edit directly
// https://github.com/cncd/pipeline/pipec
//
//
// workspace default
//
cli.StringFlag{
Name: "workspace-base",
Value: "/drone",
EnvVar: "DRONE_WORKSPACE_BASE",
},
cli.StringFlag{
Name: "workspace-path",
Value: "src",
EnvVar: "DRONE_WORKSPACE_PATH",
},
//
// netrc parameters
//
cli.StringFlag{
Name: "netrc-username",
EnvVar: "DRONE_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc-password",
EnvVar: "DRONE_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "netrc-machine",
EnvVar: "DRONE_NETRC_MACHINE",
},
//
// metadata parameters
// trigger parameters
//
cli.StringFlag{
Name: "system-arch",
Value: "linux/amd64",
EnvVar: "DRONE_SYSTEM_ARCH",
Name: "branch",
Usage: "branch name",
},
cli.StringFlag{
Name: "system-name",
Value: "pipec",
EnvVar: "DRONE_SYSTEM_NAME",
Name: "event",
Usage: "build event name (push, pull_request, etc)",
},
cli.StringFlag{
Name: "system-link",
Value: "https://github.com/cncd/pipec",
EnvVar: "DRONE_SYSTEM_LINK",
Name: "instance",
Usage: "instance hostname (e.g. drone.company.com)",
},
cli.StringFlag{
Name: "repo-name",
EnvVar: "DRONE_REPO_NAME",
Name: "ref",
Usage: "git reference",
},
cli.StringFlag{
Name: "repo-link",
EnvVar: "DRONE_REPO_LINK",
Name: "repo",
Usage: "git repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "repo-remote-url",
EnvVar: "DRONE_REPO_REMOTE",
},
cli.StringFlag{
Name: "repo-private",
EnvVar: "DRONE_REPO_PRIVATE",
},
cli.IntFlag{
Name: "build-number",
EnvVar: "DRONE_BUILD_NUMBER",
},
cli.IntFlag{
Name: "parent-build-number",
EnvVar: "DRONE_PARENT_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "build-created",
EnvVar: "DRONE_BUILD_CREATED",
},
cli.Int64Flag{
Name: "build-started",
EnvVar: "DRONE_BUILD_STARTED",
},
cli.Int64Flag{
Name: "build-finished",
EnvVar: "DRONE_BUILD_FINISHED",
},
cli.StringFlag{
Name: "build-status",
EnvVar: "DRONE_BUILD_STATUS",
},
cli.StringFlag{
Name: "build-event",
EnvVar: "DRONE_BUILD_EVENT",
},
cli.StringFlag{
Name: "build-link",
EnvVar: "DRONE_BUILD_LINK",
},
cli.StringFlag{
Name: "build-target",
EnvVar: "DRONE_BUILD_TARGET",
},
cli.StringFlag{
Name: "commit-sha",
EnvVar: "DRONE_COMMIT_SHA",
},
cli.StringFlag{
Name: "commit-ref",
EnvVar: "DRONE_COMMIT_REF",
},
cli.StringFlag{
Name: "commit-refspec",
EnvVar: "DRONE_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "commit-branch",
EnvVar: "DRONE_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit-message",
EnvVar: "DRONE_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "commit-author-name",
EnvVar: "DRONE_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "commit-author-avatar",
EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "commit-author-email",
EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "prev-build-number",
EnvVar: "DRONE_PREV_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "prev-build-created",
EnvVar: "DRONE_PREV_BUILD_CREATED",
},
cli.Int64Flag{
Name: "prev-build-started",
EnvVar: "DRONE_PREV_BUILD_STARTED",
},
cli.Int64Flag{
Name: "prev-build-finished",
EnvVar: "DRONE_PREV_BUILD_FINISHED",
},
cli.StringFlag{
Name: "prev-build-status",
EnvVar: "DRONE_PREV_BUILD_STATUS",
},
cli.StringFlag{
Name: "prev-build-event",
EnvVar: "DRONE_PREV_BUILD_EVENT",
},
cli.StringFlag{
Name: "prev-build-link",
EnvVar: "DRONE_PREV_BUILD_LINK",
},
cli.StringFlag{
Name: "prev-commit-sha",
EnvVar: "DRONE_PREV_COMMIT_SHA",
},
cli.StringFlag{
Name: "prev-commit-ref",
EnvVar: "DRONE_PREV_COMMIT_REF",
},
cli.StringFlag{
Name: "prev-commit-refspec",
EnvVar: "DRONE_PREV_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "prev-commit-branch",
EnvVar: "DRONE_PREV_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "prev-commit-message",
EnvVar: "DRONE_PREV_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "prev-commit-author-name",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "prev-commit-author-avatar",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "prev-commit-author-email",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "job-number",
EnvVar: "DRONE_JOB_NUMBER",
},
cli.StringSliceFlag{
Name: "env, e",
EnvVar: "DRONE_ENV",
Name: "deploy-to",
Usage: "deployment target (e.g. production)",
},
},
}
@ -287,211 +153,204 @@ func exec(c *cli.Context) error {
file = ".drone.yml"
}
metadata := metadataFromContext(c)
environ := metadata.Environ()
secrets := []compiler.Secret{}
for k, v := range metadata.EnvironDrone() {
environ[k] = v
}
for key, val := range metadata.Job.Matrix {
environ[key] = val
secrets = append(secrets, compiler.Secret{
Name: key,
Value: val,
})
}
drone_env := make(map[string]string)
for _, env := range c.StringSlice("env") {
envs := strings.SplitN(env, "=", 2)
drone_env[envs[0]] = envs[1]
}
tmpl, err := envsubst.ParseFile(file)
data, err := ioutil.ReadFile(file)
if err != nil {
return err
}
confstr, err := tmpl.Execute(func(name string) string {
environ := getEnv(c)
dataS, err := envsubst.Eval(string(data), func(name string) string {
return environ[name]
})
if err != nil {
return err
}
conf, err := yaml.ParseString(confstr)
// this code is temporarily in place to detect and convert
// the legacy yaml configuration file to the new format.
dataS, err = converter.ConvertString(dataS, converter.Metadata{
Filename: file,
Ref: c.String("ref"),
})
if err != nil {
return err
}
// configure volumes for local execution
volumes := c.StringSlice("volumes")
if c.Bool("local") {
var (
workspaceBase = conf.Workspace.Base
workspacePath = conf.Workspace.Path
manifest, err := yaml.ParseString(dataS)
if err != nil {
return err
}
var pipeline *yaml.Pipeline
filter := c.String("pipeline")
for _, resource := range manifest.Resources {
v, ok := resource.(*yaml.Pipeline)
if !ok {
continue
}
if filter == "" || filter == v.Name {
pipeline = v
break
}
}
if pipeline == nil {
return errors.New("cannot find pipeline")
}
trusted := c.Bool("trusted")
err = linter.Lint(pipeline, trusted)
if err != nil {
return err
}
// the user has the option to disable the git clone
// if the pipeline is being executed on the local
// codebase.
if c.Bool("clone") == false {
pipeline.Clone.Disable = true
}
comp := new(compiler.Compiler)
comp.PrivilegedFunc = compiler.DindFunc(
c.StringSlice("privileged"),
)
if workspaceBase == "" {
workspaceBase = c.String("workspace-base")
}
if workspacePath == "" {
workspacePath = c.String("workspace-path")
}
dir, _ := filepath.Abs(filepath.Dir(file))
if runtime.GOOS == "windows" {
dir = convertPathForWindows(dir)
}
volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase)
volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
}
// lint the yaml file
if lerr := linter.New(linter.WithTrusted(true)).Lint(conf); lerr != nil {
return lerr
}
// compiles the yaml file
compiled := compiler.New(
compiler.WithEscalated(
c.StringSlice("privileged")...,
comp.SkipFunc = compiler.SkipFunc(
compiler.SkipData{
Branch: environ["DRONE_BRANCH"],
Event: environ["DRONE_EVENT"],
Instance: environ["DRONE_SYSTEM_HOST"],
Ref: environ["DRONE_COMMIT_REF"],
Repo: environ["DRONE_REPO"],
Target: environ["DRONE_DEPLOY_TO"],
},
)
transforms := []func(*engine.Spec){
transform.Include(
c.StringSlice("include"),
),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
c.String("workspace-base"),
c.String("workspace-path"),
transform.Exclude(
c.StringSlice("exclude"),
),
compiler.WithNetworks(
c.StringSlice("network")...,
transform.ResumeAt(
c.String("resume-at"),
),
compiler.WithPrefix(
c.String("prefix"),
transform.WithAuths(
toRegistry(
c.StringSlice("registry"),
),
compiler.WithProxy(),
compiler.WithLocal(
c.Bool("local"),
),
compiler.WithNetrc(
transform.WithEnviron(
readParams(
c.String("env-file"),
),
),
transform.WithEnviron(environ),
transform.WithLables(nil),
transform.WithLimits(0, 0),
transform.WithNetrc(
c.String("netrc-machine"),
c.String("netrc-username"),
c.String("netrc-password"),
c.String("netrc-machine"),
),
compiler.WithMetadata(metadata),
compiler.WithSecret(secrets...),
compiler.WithEnviron(drone_env),
).Compile(conf)
transform.WithNetworks(
c.StringSlice("network"),
),
transform.WithProxy(),
transform.WithSecrets(
readParams(
c.String("secret-file"),
),
),
transform.WithVolumeSlice(
c.StringSlice("volume"),
),
}
if c.Bool("clone") == false {
pwd, _ := os.Getwd()
comp.WorkspaceMountFunc = compiler.MountHostWorkspace
comp.WorkspaceFunc = compiler.CreateHostWorkspace(pwd)
}
comp.TransformFunc = transform.Combine(transforms...)
ir := comp.Compile(pipeline)
ctx, cancel := context.WithTimeout(
context.Background(),
c.Duration("timeout"),
)
ctx = signal.WithContext(ctx)
defer cancel()
// creates a docker-based engine. eventually we will
// include the kubernetes and vmware fusion engines.
engine, err := docker.NewEnv()
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
defer cancel()
ctx = interrupt.WithContext(ctx)
// creates a hook to print the step output to stdout,
// with per-step color coding if a tty.
hooks := &runtime.Hook{}
hooks.BeforeEach = func(s *runtime.State) error {
s.Step.Envs["CI_BUILD_STATUS"] = "success"
s.Step.Envs["CI_BUILD_STARTED"] = strconv.FormatInt(s.Runtime.Time, 10)
s.Step.Envs["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
s.Step.Envs["DRONE_BUILD_STATUS"] = "success"
s.Step.Envs["DRONE_BUILD_STARTED"] = strconv.FormatInt(s.Runtime.Time, 10)
s.Step.Envs["DRONE_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
return pipeline.New(compiled,
pipeline.WithContext(ctx),
pipeline.WithTracer(pipeline.DefaultTracer),
pipeline.WithLogger(defaultLogger),
pipeline.WithEngine(engine),
).Run()
}
s.Step.Envs["CI_JOB_STATUS"] = "success"
s.Step.Envs["CI_JOB_STARTED"] = strconv.FormatInt(s.Runtime.Time, 10)
s.Step.Envs["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
s.Step.Envs["DRONE_JOB_STATUS"] = "success"
s.Step.Envs["DRONE_JOB_STARTED"] = strconv.FormatInt(s.Runtime.Time, 10)
s.Step.Envs["DRONE_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
return frontend.Metadata{
Repo: frontend.Repo{
Name: c.String("repo-name"),
Link: c.String("repo-link"),
Remote: c.String("repo-remote-url"),
Private: c.Bool("repo-private"),
},
Curr: frontend.Build{
Number: c.Int("build-number"),
Parent: c.Int("parent-build-number"),
Created: c.Int64("build-created"),
Started: c.Int64("build-started"),
Finished: c.Int64("build-finished"),
Status: c.String("build-status"),
Event: c.String("build-event"),
Link: c.String("build-link"),
Target: c.String("build-target"),
Commit: frontend.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
Refspec: c.String("commit-refspec"),
Branch: c.String("commit-branch"),
Message: c.String("commit-message"),
Author: frontend.Author{
Name: c.String("commit-author-name"),
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
},
},
Prev: frontend.Build{
Number: c.Int("prev-build-number"),
Created: c.Int64("prev-build-created"),
Started: c.Int64("prev-build-started"),
Finished: c.Int64("prev-build-finished"),
Status: c.String("prev-build-status"),
Event: c.String("prev-build-event"),
Link: c.String("prev-build-link"),
Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),
Refspec: c.String("prev-commit-refspec"),
Branch: c.String("prev-commit-branch"),
Message: c.String("prev-commit-message"),
Author: frontend.Author{
Name: c.String("prev-commit-author-name"),
Email: c.String("prev-commit-author-email"),
Avatar: c.String("prev-commit-author-avatar"),
},
},
},
Job: frontend.Job{
Number: c.Int("job-number"),
Matrix: availableEnvironment(),
},
Sys: frontend.System{
Name: c.String("system-name"),
Link: c.String("system-link"),
Arch: c.String("system-arch"),
},
if s.Runtime.Error != nil {
s.Step.Envs["CI_BUILD_STATUS"] = "failure"
s.Step.Envs["CI_JOB_STATUS"] = "failure"
s.Step.Envs["DRONE_BUILD_STATUS"] = "failure"
s.Step.Envs["DRONE_JOB_STATUS"] = "failure"
}
}
func availableEnvironment() map[string]string {
result := make(map[string]string, 0)
for _, env := range os.Environ() {
pair := strings.SplitN(env, "=", 2)
result[pair[0]] = pair[1]
}
return result
}
func convertPathForWindows(path string) string {
base := filepath.VolumeName(path)
if len(base) == 2 {
path = strings.TrimPrefix(path, base)
base = strings.ToLower(strings.TrimSuffix(base, ":"))
return "/" + base + filepath.ToSlash(path)
}
return filepath.ToSlash(path)
}
var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
part, err := rc.NextPart()
if err != nil {
return err
}
logstream := NewLineWriter(proc.Alias)
io.Copy(logstream, part)
return nil
})
}
hooks.GotLine = term.WriteLine(os.Stdout)
if tty {
hooks.GotLine = term.WriteLinePretty(
colorable.NewColorableStdout(),
)
}
return runtime.New(
runtime.WithEngine(engine),
runtime.WithConfig(ir),
runtime.WithHooks(hooks),
).Run(ctx)
}
// helper function converts a slice of urls to a slice
// of docker registry credentials.
func toRegistry(items []string) []*engine.DockerAuth {
auths := []*engine.DockerAuth{}
for _, item := range items {
uri, err := url.Parse(item)
if err != nil {
continue // skip invalid
}
user := uri.User.Username()
pass, _ := uri.User.Password()
uri.User = nil
auths = append(auths, &engine.DockerAuth{
Address: uri.String(),
Username: user,
Password: pass,
})
}
return auths
}
// helper function reads secrets from a key-value file.
func readParams(path string) map[string]string {
data, _ := godotenv.Read(path)
return data
}

47
drone/format/format.go Normal file

@ -0,0 +1,47 @@
package format
import (
"bytes"
"io"
"io/ioutil"
"os"
"github.com/drone/drone-yaml/yaml"
"github.com/drone/drone-yaml/yaml/pretty"
"github.com/urfave/cli"
)
// Command exports the fmt command.
var Command = cli.Command{
Name: "fmt",
Usage: "format the yaml file",
ArgsUsage: "<source>",
Action: format,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "save",
Usage: "save result to source",
},
},
}
func format(c *cli.Context) error {
path := c.Args().First()
if path == "" {
path = ".drone.yml"
}
manifest, err := yaml.ParseFile(path)
if err != nil {
return err
}
buf := new(bytes.Buffer)
pretty.Print(buf, manifest)
if c.Bool("save") {
return ioutil.WriteFile(path, buf.Bytes(), 0644)
}
_, err = io.Copy(os.Stderr, buf)
return err
}

@ -4,9 +4,9 @@ import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
// Command exports the info command.
@ -20,7 +20,6 @@ var Command = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplInfo,
Hidden: true,
},
},
}
@ -36,7 +35,7 @@ func info(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}

@ -49,6 +49,10 @@ func NewClient(c *cli.Context) (drone.Client, error) {
},
)
auther.CheckRedirect = func(*http.Request, []*http.Request) error {
return fmt.Errorf("Attempting to redirect the requests. Did you configure the correct drone server address?")
}
trans, _ := auther.Transport.(*oauth2.Transport)
if len(socks) != 0 && !socksoff {
@ -79,7 +83,7 @@ func NewAutoscaleClient(c *cli.Context) (drone.Client, error) {
}
autoscaler := c.GlobalString("autoscaler")
if autoscaler == "" {
return nil, fmt.Errorf("Please provide the autoscaler address")
return nil, fmt.Errorf("Please provide the autoscaler address.")
}
client.SetAddress(
strings.TrimSuffix(autoscaler, "/"),
@ -91,7 +95,7 @@ func NewAutoscaleClient(c *cli.Context) (drone.Client, error) {
func ParseRepo(str string) (user, repo string, err error) {
var parts = strings.Split(str, "/")
if len(parts) != 2 {
err = fmt.Errorf("Error: Invalid or missing repository. eg octocat/hello-world.")
err = fmt.Errorf("Error: Invalid or missing repository (e.g. octocat/hello-world).")
return
}
user = parts[0]

@ -1,9 +1,16 @@
package jsonnet
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strings"
"github.com/drone/drone-yaml/yaml"
"github.com/drone/drone-yaml/yaml/pretty"
"github.com/fatih/color"
"github.com/google/go-jsonnet"
"github.com/urfave/cli"
@ -20,67 +27,120 @@ var Command = cli.Command{
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "source",
Usage: "Source file",
Value: ".drone.jsonnet",
},
cli.StringFlag{
Name: "target",
Usage: "target file",
Value: ".drone.yml",
},
cli.BoolFlag{
Name: "string",
Hidden: true,
Name: "stream",
Usage: "Write output as a YAML stream.",
},
cli.IntFlag{
Name: "max-stack",
Usage: "number of allowed stack frames",
Value: 500,
},
cli.IntFlag{
Name: "max-trace",
Usage: "max length of stack trace before cropping",
Value: 20,
cli.BoolTFlag{
Name: "format",
Usage: "Write output as formatted YAML",
},
cli.BoolFlag{
Name: "stdout",
Usage: "write the json document to stdout",
Usage: "Write output to stdout",
},
cli.BoolFlag{
Name: "string",
Usage: "Expect a string, manifest as plain text",
},
cli.StringSliceFlag{
Name: "extVar, V",
Usage: "Pass extVars to Jsonnet (can be specified multiple times)",
},
},
}
func generate(c *cli.Context) error {
input := c.Args().Get(0)
if input == "" {
input = ".drone.jsonnet"
}
output := c.Args().Get(1)
if output == "" {
output = ".drone.yml"
}
source := c.String("source")
target := c.String("target")
snippet, err := ioutil.ReadFile(input)
data, err := ioutil.ReadFile(source)
if err != nil {
return err
}
vm := jsonnet.MakeVM()
vm.KeepOrder = true
vm.MaxStack = 500
vm.StringOutput = c.Bool("string")
vm.MaxStack = c.Int("max-stack")
// vm.ExtVar
// vm.ExtCode
// vm.TLAVar
// vm.TLACode
// vm.Importer(&jsonnet.FileImporter{})
vm.ErrorFormatter.SetMaxStackTraceSize(
c.Int("max-trace"),
)
vm.ErrorFormatter.SetMaxStackTraceSize(20)
vm.ErrorFormatter.SetColorFormatter(
color.New(color.FgRed).Fprintf,
)
raw, err := vm.EvaluateSnippet(input, string(snippet))
// register native functions
RegisterNativeFuncs(vm)
// extVars
vars := c.StringSlice("extVar")
for _, v := range vars {
name, value, err := getVarVal(v)
if err != nil {
return err
}
vm.ExtVar(name, value)
}
buf := new(bytes.Buffer)
if c.Bool("stream") {
docs, err := vm.EvaluateSnippetStream(source, string(data))
if err != nil {
return err
}
for _, doc := range docs {
buf.WriteString("---")
buf.WriteString("\n")
buf.WriteString(doc)
}
} else {
result, err := vm.EvaluateSnippet(source, string(data))
if err != nil {
return err
}
buf.WriteString(result)
}
// the yaml file is parsed and formatted by default. This
// can be disabled for --format=false.
if c.BoolT("format") {
manifest, err := yaml.Parse(buf)
if err != nil {
return err
}
buf.Reset()
pretty.Print(buf, manifest)
}
// the user can optionally write the yaml to stdout. This
// is useful for debugging purposes without mutating an
// existing file.
if c.Bool("stdout") {
println(raw)
io.Copy(os.Stdout, buf)
return nil
}
return ioutil.WriteFile(output, []byte(raw), 0644)
return ioutil.WriteFile(target, buf.Bytes(), 0644)
}
// https://github.com/google/go-jsonnet/blob/master/cmd/jsonnet/cmd.go#L149
func getVarVal(s string) (string, string, error) {
parts := strings.SplitN(s, "=", 2)
name := parts[0]
if len(parts) == 1 {
content, exists := os.LookupEnv(name)
if exists {
return name, content, nil
}
return "", "", fmt.Errorf("environment variable %v was undefined", name)
}
return name, parts[1], nil
}

@ -0,0 +1,45 @@
package jsonnet
import (
// "bytes"
// "encoding/json"
// "io"
jsonnet "github.com/google/go-jsonnet"
// jsonnetAst "github.com/google/go-jsonnet/ast"
// "k8s.io/apimachinery/pkg/util/yaml"
)
// RegisterNativeFuncs adds kubecfg's native jsonnet functions to provided VM
func RegisterNativeFuncs(vm *jsonnet.VM) {
// vm.NativeFunction(&jsonnet.NativeFunction{
// Name: "parseJson",
// Params: []jsonnetAst.Identifier{"json"},
// Func: func(args []interface{}) (res interface{}, err error) {
// data := []byte(args[0].(string))
// err = json.Unmarshal(data, &res)
// return
// },
// })
// vm.NativeFunction(&jsonnet.NativeFunction{
// Name: "parseYaml",
// Params: []jsonnetAst.Identifier{"yaml"},
// Func: func(args []interface{}) (res interface{}, err error) {
// ret := []interface{}{}
// data := []byte(args[0].(string))
// d := yaml.NewYAMLToJSONDecoder(bytes.NewReader(data))
// for {
// var doc interface{}
// if err := d.Decode(&doc); err != nil {
// if err == io.EOF {
// break
// }
// return nil, err
// }
// ret = append(ret, doc)
// }
// return ret, nil
// },
// })
}

41
drone/lint/lint.go Normal file

@ -0,0 +1,41 @@
package lint
import (
"github.com/drone/drone-yaml/yaml"
"github.com/drone/drone-yaml/yaml/linter"
"github.com/urfave/cli"
)
// Command exports the linter command.
var Command = cli.Command{
Name: "lint",
Usage: "lint the yaml file",
ArgsUsage: "<source>",
Action: lint,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "trusted",
Usage: "is the yaml trustable",
},
},
}
func lint(c *cli.Context) error {
path := c.Args().First()
if path == "" {
path = ".drone.yml"
}
manifest, err := yaml.ParseFile(path)
if err != nil {
return err
}
for _, resource := range manifest.Resources {
if err := linter.Lint(resource, c.Bool("trusted")); err != nil {
return err
}
}
return nil
}

@ -8,5 +8,6 @@ var Command = cli.Command{
Usage: "manage logs",
Subcommands: []cli.Command{
logPurgeCmd,
logViewCmd,
},
}

@ -11,7 +11,7 @@ import (
var logPurgeCmd = cli.Command{
Name: "purge",
Usage: "purge a log",
ArgsUsage: "<repo/name> <build>",
ArgsUsage: "<repo/name> <build> <stage> <step>",
Action: logPurge,
}
@ -25,13 +25,21 @@ func logPurge(c *cli.Context) (err error) {
if err != nil {
return err
}
stage, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
step, err := strconv.Atoi(c.Args().Get(3))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.LogsPurge(owner, name, number)
err = client.LogsPurge(owner, name, number, stage, step)
if err != nil {
return err
}

50
drone/log/log_view.go Normal file

@ -0,0 +1,50 @@
package log
import (
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var logViewCmd = cli.Command{
Name: "view",
Usage: "display the step logs",
ArgsUsage: "<repo/name> <build> <stage> <step>",
Action: logView,
}
func logView(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
stage, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
step, err := strconv.Atoi(c.Args().Get(3))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
lines, err := client.Logs(owner, name, number, stage, step)
if err != nil {
return err
}
for _, line := range lines {
print(line.Message)
}
return nil
}

@ -6,15 +6,23 @@ import (
"github.com/drone/drone-cli/drone/autoscale"
"github.com/drone/drone-cli/drone/build"
"github.com/drone/drone-cli/drone/deploy"
"github.com/drone/drone-cli/drone/convert"
"github.com/drone/drone-cli/drone/cron"
"github.com/drone/drone-cli/drone/encrypt"
"github.com/drone/drone-cli/drone/exec"
"github.com/drone/drone-cli/drone/format"
"github.com/drone/drone-cli/drone/info"
"github.com/drone/drone-cli/drone/jsonnet"
"github.com/drone/drone-cli/drone/lint"
"github.com/drone/drone-cli/drone/log"
"github.com/drone/drone-cli/drone/registry"
"github.com/drone/drone-cli/drone/orgsecret"
"github.com/drone/drone-cli/drone/plugins"
"github.com/drone/drone-cli/drone/queue"
"github.com/drone/drone-cli/drone/repo"
"github.com/drone/drone-cli/drone/secret"
"github.com/drone/drone-cli/drone/server"
"github.com/drone/drone-cli/drone/sign"
"github.com/drone/drone-cli/drone/starlark"
"github.com/drone/drone-cli/drone/user"
_ "github.com/joho/godotenv/autoload"
@ -68,17 +76,25 @@ func main() {
}
app.Commands = []cli.Command{
build.Command,
cron.Command,
log.Command,
deploy.Command,
encrypt.Command,
exec.Command,
info.Command,
registry.Command,
secret.Command,
repo.Command,
user.Command,
secret.Command,
server.Command,
queue.Command,
orgsecret.Command,
autoscale.Command,
format.Command,
convert.Command,
lint.Command,
sign.Command,
jsonnet.Command,
starlark.Command,
plugins.Command,
}
if err := app.Run(os.Args); err != nil {

24
drone/node/node.go Normal file

@ -0,0 +1,24 @@
package node
import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "node",
Usage: "manage nodes",
Hidden: true,
Subcommands: []cli.Command{
nodeListCmd,
nodeInfoCmd,
nodeCreateCmd,
// nodeUpdateCmd,
// nodeDeleteCmd,
// nodePauseCmd,
// nodeUnpauseCmd,
// nodeLockCmd,
// nodeUnlockCmd,
// nodeInitCmd,
nodeImportCmd,
// nodeKeygenCmd,
},
}

149
drone/node/node_create.go Normal file

@ -0,0 +1,149 @@
package node
import (
"html/template"
"io/ioutil"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var nodeCreateCmd = cli.Command{
Name: "add",
Usage: "adds a node",
Action: nodeCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "node name",
},
cli.StringFlag{
Name: "hostname",
Usage: "node hostname or ip address",
},
cli.StringFlag{
Name: "ca-key",
Usage: "path to ca key",
},
cli.StringFlag{
Name: "ca-cert",
Usage: "path to ca cert",
},
cli.StringFlag{
Name: "tls-key",
Usage: "path to tls key",
},
cli.StringFlag{
Name: "tls-cert",
Usage: "path to tls cert",
},
cli.StringFlag{
Name: "tls-server-name",
Usage: "tls server name",
},
cli.IntFlag{
Name: "capacity",
Usage: "node capacity",
Value: 2,
},
cli.StringFlag{
Name: "os",
Usage: "node os",
Value: "linux",
},
cli.StringFlag{
Name: "arch",
Usage: "node arch",
Value: "amd64",
},
cli.StringFlag{
Name: "region",
Usage: "node region",
},
cli.StringFlag{
Name: "instance",
Usage: "node instance type",
},
cli.StringFlag{
Name: "image",
Usage: "node image (i.e. ami)",
},
cli.StringFlag{
Name: "provider",
Usage: "node hosting provider (e.g. amazon)",
},
cli.BoolFlag{
Name: "paused",
Usage: "node is paused",
},
cli.BoolFlag{
Name: "protected",
Usage: "node is protected from deletion",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplNodeInfo,
},
},
}
func nodeCreate(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
cakey, err := ioutil.ReadFile(c.String("ca-key"))
if err != nil {
return err
}
cacert, err := ioutil.ReadFile(c.String("ca-cert"))
if err != nil {
return err
}
tlskey, err := ioutil.ReadFile(c.String("tls-key"))
if err != nil {
return err
}
tlscert, err := ioutil.ReadFile(c.String("tls-cert"))
if err != nil {
return err
}
node := &drone.Node{
UID: c.String("id"),
Provider: c.String("provider"),
State: c.String("state"),
Name: c.String("name"),
Image: c.String("image"),
Region: c.String("region"),
Size: c.String("instance"),
OS: c.String("os"),
Arch: c.String("arch"),
Address: c.String("hostname"),
Capacity: c.Int("capacity"),
CAKey: cakey,
CACert: cacert,
TLSKey: tlskey,
TLSCert: tlscert,
TLSName: c.String("tls-server-name"),
Paused: c.Bool("paused"),
Protected: c.Bool("protected"),
}
_, err = client.NodeCreate(node)
if err != nil {
return err
}
format := c.String("format")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, node)
}

@ -0,0 +1 @@
package node

192
drone/node/node_import.go Normal file

@ -0,0 +1,192 @@
package node
import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
func getMachineHome() (path string) {
user, err := user.Current()
if err == nil {
return filepath.Join(user.HomeDir, ".docker", "machine")
}
return
}
var nodeImportCmd = cli.Command{
Name: "import",
Usage: "import a node from docker-machine",
Action: nodeImport,
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "node name",
},
cli.IntFlag{
Name: "capacity",
Usage: "node capacity",
Value: 2,
},
cli.StringFlag{
Name: "os",
Usage: "node os",
Value: "linux",
},
cli.StringFlag{
Name: "arch",
Usage: "node arch",
Value: "amd64",
},
cli.BoolFlag{
Name: "paused",
Usage: "node is paused",
},
cli.BoolFlag{
Name: "protected",
Usage: "node is protected from deletion",
},
cli.StringFlag{
Name: "storage-path",
Usage: "docker machine storage path",
Value: getMachineHome(),
EnvVar: "MACHINE_STORAGE_PATH",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplNodeInfo,
},
},
}
func nodeImport(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
name := c.String("name")
if name == "" {
name = c.Args().First()
}
home := c.String("storage-path")
base := filepath.Join(home, "machines", name)
conf := new(machine)
confpath := filepath.Join(base, "config.json")
confdata, err := ioutil.ReadFile(confpath)
if err != nil {
return err
}
err = json.Unmarshal(confdata, conf)
if err != nil {
return err
}
cakey, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.CaPrivateKeyPath)
if err != nil {
return err
}
cacert, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.CaCertPath)
if err != nil {
return err
}
tlskey, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.ClientKeyPath)
if err != nil {
return err
}
tlscert, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.ClientCertPath)
if err != nil {
return err
}
node := &drone.Node{
UID: fmt.Sprint(conf.Driver.DropletID),
Provider: c.String("provider"),
State: c.String("state"),
Name: conf.Driver.MachineName,
Image: conf.Driver.Image,
Region: conf.Driver.Region,
Size: conf.Driver.Size,
OS: c.String("os"),
Arch: c.String("arch"),
Address: conf.Driver.IPAddress,
Capacity: 2,
CAKey: cakey,
CACert: cacert,
TLSKey: tlskey,
TLSCert: tlscert,
Paused: c.Bool("paused"),
Protected: c.Bool("protected"),
}
_, err = client.NodeCreate(node)
if err != nil {
return err
}
format := c.String("format")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, node)
}
type machine struct {
DriverName string
Driver struct {
IPAddress string `json:"IPAddress"`
MachineName string `json:"MachineName"`
SSHUser string `json:"SSHUser"`
SSHPort int `json:"SSHPort"`
SSHKeyPath string `json:"SSHKeyPath"`
StorePath string `json:"StorePath"`
SwarmMaster bool `json:"SwarmMaster"`
SwarmHost string `json:"SwarmHost"`
SwarmDiscovery string `json:"SwarmDiscovery"`
AccessToken string `json:"AccessToken"`
DropletID int `json:"DropletID"`
DropletName string `json:"DropletName"`
Image string `json:"Image"`
Region string `json:"Region"`
SSHKeyID int `json:"SSHKeyID"`
SSHKeyFingerprint string `json:"SSHKeyFingerprint"`
SSHKey string `json:"SSHKey"`
Size string `json:"Size"`
IPv6 bool `json:"IPv6"`
Backups bool `json:"Backups"`
PrivateNetworking bool `json:"PrivateNetworking"`
UserDataFile string `json:"UserDataFile"`
Monitoring bool `json:"Monitoring"`
Tags string `json:"Tags"`
}
HostOptions struct {
AuthOptions struct {
CertDir string `json:"CertDir"`
CaCertPath string `json:"CaCertPath"`
CaPrivateKeyPath string `json:"CaPrivateKeyPath"`
CaCertRemotePath string `json:"CaCertRemotePath"`
ServerCertPath string `json:"ServerCertPath"`
ServerKeyPath string `json:"ServerKeyPath"`
ClientKeyPath string `json:"ClientKeyPath"`
ServerCertRemotePath string `json:"ServerCertRemotePath"`
ServerKeyRemotePath string `json:"ServerKeyRemotePath"`
ClientCertPath string `json:"ClientCertPath"`
ServerCertSANs []interface{} `json:"ServerCertSANs"`
StorePath string `json:"StorePath"`
}
}
}

@ -0,0 +1,155 @@
package node
import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var nodeImportAllCmd = cli.Command{
Name: "import-all",
Usage: "import all node from docker-machine",
Action: nodeImportAll,
Flags: []cli.Flag{
cli.IntFlag{
Name: "capacity",
Usage: "node capacity",
Value: 2,
},
cli.StringFlag{
Name: "os",
Usage: "node os",
Value: "linux",
},
cli.StringFlag{
Name: "arch",
Usage: "node arch",
Value: "amd64",
},
cli.BoolFlag{
Name: "paused",
Usage: "node is paused",
},
cli.BoolFlag{
Name: "protected",
Usage: "node is protected from deletion",
},
cli.StringFlag{
Name: "storage-path",
Usage: "docker machine storage path",
Value: getMachineHome(),
EnvVar: "MACHINE_STORAGE_PATH",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplNodeInfo,
},
},
}
func nodeImportAll(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
home := c.String("storage-path")
matches, err := filepath.Glob(filepath.Join(home, "machines", "*"))
if err != nil {
return err
}
nodes, err := client.NodeList()
if err != nil {
return err
}
nodeIndex := map[string]*drone.Node{}
for _, node := range nodes {
nodeIndex[node.Name] = node
}
format := c.String("format") + "\n"
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, name := range matches {
base := filepath.Join(home, "machines", name)
// if the node already exists it should be
// ignored by the system.
existing, ok := nodeIndex[name]
if ok {
tmpl.Execute(os.Stdout, existing)
continue
}
conf := new(machine)
confpath := filepath.Join(base, "config.json")
confdata, err := ioutil.ReadFile(confpath)
if err != nil {
return err
}
err = json.Unmarshal(confdata, conf)
if err != nil {
return err
}
cakey, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.CaPrivateKeyPath)
if err != nil {
return err
}
cacert, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.CaCertPath)
if err != nil {
return err
}
tlskey, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.ClientKeyPath)
if err != nil {
return err
}
tlscert, err := ioutil.ReadFile(conf.HostOptions.AuthOptions.ClientCertPath)
if err != nil {
return err
}
node := &drone.Node{
UID: fmt.Sprint(conf.Driver.DropletID),
Provider: c.String("provider"),
State: c.String("state"),
Name: conf.Driver.MachineName,
Image: conf.Driver.Image,
Region: conf.Driver.Region,
Size: conf.Driver.Size,
OS: c.String("os"),
Arch: c.String("arch"),
Address: conf.Driver.IPAddress,
Capacity: 2,
CAKey: cakey,
CACert: cacert,
TLSKey: tlskey,
TLSCert: tlscert,
Paused: c.Bool("paused"),
Protected: c.Bool("protected"),
}
_, err = client.NodeCreate(node)
if err != nil {
return err
}
tmpl.Execute(os.Stdout, node)
}
return nil
}

51
drone/node/node_info.go Normal file

@ -0,0 +1,51 @@
package node
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var nodeInfoCmd = cli.Command{
Name: "info",
Usage: "display node info",
Action: nodeInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplNodeInfo,
},
},
}
func nodeInfo(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
name := c.Args().First()
node, err := client.Node(name)
if err != nil {
return err
}
format := c.String("format")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, node)
}
var tmplNodeInfo = "\x1b[33m{{ .Name }} \x1b[0m" + `
Address: {{ .Address }}
Region: {{ .Region }}
Instance: {{ .Size }}
OS: {{ .OS }}
Arch: {{ .Arch }}
Locked: {{ .Protected }}
Paused: {{ .Paused }}
`

1
drone/node/node_init.go Normal file

@ -0,0 +1 @@
package node

@ -0,0 +1 @@
package node

49
drone/node/node_list.go Normal file

@ -0,0 +1,49 @@
package node
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var nodeListCmd = cli.Command{
Name: "ls",
Usage: "list nodes",
Action: nodeList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplNodeList,
},
},
}
func nodeList(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
list, err := client.NodeList()
if err != nil {
return err
}
format := c.String("format") + "\n"
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, cron := range list {
tmpl.Execute(os.Stdout, cron)
}
return nil
}
// template for node list information
var tmplNodeList = "\x1b[33m{{ .Name }} \x1b[0m" + `
Address: {{ .Address }}
Platform: {{ .OS }}/{{ .Arch }}
`

@ -0,0 +1 @@
package node

16
drone/orgsecret/secret.go Normal file

@ -0,0 +1,16 @@
package orgsecret
import "github.com/urfave/cli"
// Command exports the secret command.
var Command = cli.Command{
Name: "orgsecret",
Usage: "manage organization secrets",
Subcommands: []cli.Command{
secretCreateCmd,
secretDeleteCmd,
secretUpdateCmd,
secretInfoCmd,
secretListCmd,
},
}

@ -0,0 +1,57 @@
package orgsecret
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var secretCreateCmd = cli.Command{
Name: "add",
Usage: "adds a secret",
ArgsUsage: "[organization] [name] [data]",
Action: secretCreate,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "allow-pull-request",
Usage: "permit read access to pull requests",
},
cli.BoolFlag{
Name: "allow-push-on-pull-request",
Usage: "permit write access to pull requests (e.g. allow docker push)",
},
},
}
func secretCreate(c *cli.Context) error {
var (
namespace = c.Args().First()
name = c.Args().Get(1)
data = c.Args().Get(2)
)
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret := &drone.Secret{
Name: name,
Data: data,
PullRequest: c.Bool("allow-pull-request"),
PullRequestPush: c.Bool("allow-push-on-pull-request"),
}
if strings.HasPrefix(secret.Data, "@") {
path := strings.TrimPrefix(secret.Data, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Data = string(out)
}
_, err = client.OrgSecretCreate(namespace, secret)
return err
}

@ -0,0 +1,45 @@
package orgsecret
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var secretInfoCmd = cli.Command{
Name: "info",
Usage: "display secret info",
ArgsUsage: "[organization] [name]",
Action: secretInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
},
},
}
func secretInfo(c *cli.Context) error {
var (
namespace = c.Args().First()
name = c.Args().Get(1)
format = c.String("format") + "\n"
)
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret, err := client.OrgSecret(namespace, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, secret)
}

@ -0,0 +1,62 @@
package orgsecret
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var secretListCmd = cli.Command{
Name: "ls",
Usage: "list secrets",
ArgsUsage: "",
Action: secretList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "filter",
Usage: "filter output by organization",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
},
},
}
func secretList(c *cli.Context) error {
filter := c.String("filter")
format := c.String("format") + "\n"
client, err := internal.NewClient(c)
if err != nil {
return err
}
var list []*drone.Secret
if filter == "" {
list, err = client.OrgSecretListAll()
} else {
list, err = client.OrgSecretList(filter)
}
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, secret := range list {
tmpl.Execute(os.Stdout, secret)
}
return nil
}
// template for secret list items
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
Organization: {{ .Namespace }}
Pull Request Read: {{ .PullRequest }}
Pull Request Write: {{ .PullRequestPush }}
`

@ -0,0 +1,27 @@
package orgsecret
import (
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var secretDeleteCmd = cli.Command{
Name: "rm",
Usage: "remove a secret",
ArgsUsage: "[organization] [name]",
Action: secretDelete,
Flags: []cli.Flag{},
}
func secretDelete(c *cli.Context) error {
var (
namespace = c.Args().First()
name = c.Args().Get(1)
)
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.OrgSecretDelete(namespace, name)
}

@ -0,0 +1,56 @@
package orgsecret
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var secretUpdateCmd = cli.Command{
Name: "update",
Usage: "update a secret",
ArgsUsage: "[organization] [name] [data]",
Action: secretUpdate,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "allow-pull-request",
Usage: "permit read access to pull requests",
},
cli.BoolFlag{
Name: "allow-push-on-pull-request",
Usage: "permit write access to pull requests (e.g. allow docker push)",
},
},
}
func secretUpdate(c *cli.Context) error {
var (
namespace = c.Args().First()
name = c.Args().Get(1)
data = c.Args().Get(2)
)
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret := &drone.Secret{
Name: name,
Data: data,
PullRequest: c.Bool("allow-pull-request"),
PullRequestPush: c.Bool("allow-push-on-pull-request"),
}
if strings.HasPrefix(secret.Data, "@") {
path := strings.TrimPrefix(secret.Data, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Data = string(out)
}
_, err = client.OrgSecretUpdate(namespace, secret)
return err
}

@ -0,0 +1,64 @@
package admit
import (
"context"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/admission"
"github.com/urfave/cli"
)
// Command exports the admission command set.
var Command = cli.Command{
Name: "admit",
Usage: "test user admission",
ArgsUsage: "user",
Action: admit,
Flags: []cli.Flag{
cli.StringFlag{
Name: "user",
Usage: "username",
},
cli.StringFlag{
Name: "endpoint",
Usage: "plugin endpoint",
EnvVar: "DRONE_ADMISSION_ENDPOINT",
},
cli.StringFlag{
Name: "secret",
Usage: "plugin secret",
EnvVar: "DRONE_ADMISSION_SECRET",
},
cli.StringFlag{
Name: "ssl-skip-verify",
Usage: "plugin ssl verification disabled",
EnvVar: "DRONE_ADMISSION_SKIP_VERIFY",
},
},
}
func admit(c *cli.Context) error {
login := c.String("user")
if login == "" {
login = c.Args().First()
}
req := &admission.Request{
User: drone.User{
Login: login,
},
}
client := admission.Client(
c.String("endpoint"),
c.String("secret"),
c.Bool("ssl-skip-verify"),
)
_, err := client.Admit(context.Background(), req)
if err != nil {
return err
}
return nil
}

@ -0,0 +1,12 @@
package config
import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "config",
Usage: "config plugin helpers",
Subcommands: []cli.Command{
configFindCmd,
},
}

106
drone/plugins/config/get.go Normal file

@ -0,0 +1,106 @@
package config
import (
"context"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/config"
"github.com/urfave/cli"
)
var configFindCmd = cli.Command{
Name: "get",
Usage: "get the pipeline configuration",
ArgsUsage: "[repo/name]",
Action: configFind,
Flags: []cli.Flag{
cli.StringFlag{
Name: "ref",
Usage: "git reference",
Value: "refs/heads/master",
},
cli.StringFlag{
Name: "source",
Usage: "source branch",
Value: "master",
},
cli.StringFlag{
Name: "target",
Usage: "target branch",
Value: "master",
},
cli.StringFlag{
Name: "before",
Usage: "commit sha before the change",
},
cli.StringFlag{
Name: "after",
Usage: "commit sha after the change",
},
cli.StringFlag{
Name: "path",
Usage: "configuration file path",
Value: ".drone.jsonnet",
},
// TODO(bradrydzewski) these parameters should
// be defined globally for all plugin commands.
cli.StringFlag{
Name: "endpoint",
Usage: "plugin endpoint",
EnvVar: "DRONE_YAML_ENDPOINT",
},
cli.StringFlag{
Name: "secret",
Usage: "plugin secret",
EnvVar: "DRONE_YAML_SECRET",
},
cli.StringFlag{
Name: "ssl-skip-verify",
Usage: "plugin ssl verification disabled",
EnvVar: "DRONE_YAML_SKIP_VERIFY",
},
},
}
func configFind(c *cli.Context) error {
slug := c.Args().First()
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
repo := drone.Repo{
Namespace: owner,
Name: name,
Slug: slug,
Config: c.String("path"),
}
build := drone.Build{
Ref: c.String("ref"),
Before: c.String("before"),
After: c.String("after"),
Source: c.String("source"),
Target: c.String("target"),
}
req := &config.Request{
Repo: repo,
Build: build,
}
client := config.Client(
c.String("endpoint"),
c.String("secret"),
c.Bool("ssl-skip-verify"),
)
res, err := client.Find(context.Background(), req)
if err != nil {
return err
}
println(res.Data)
return nil
}

@ -0,0 +1,122 @@
package convert
import (
"context"
"io/ioutil"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/converter"
"github.com/urfave/cli"
)
// Command exports the registry command set.
var Command = cli.Command{
Name: "convert",
Usage: "convert the pipeline configuration",
ArgsUsage: "[repo/name]",
Action: convert,
Flags: []cli.Flag{
cli.StringFlag{
Name: "path",
Usage: "path to the configuration file",
},
cli.StringFlag{
Name: "ref",
Usage: "git reference",
Value: "refs/heads/master",
},
cli.StringFlag{
Name: "source",
Usage: "source branch",
Value: "master",
},
cli.StringFlag{
Name: "target",
Usage: "target branch",
Value: "master",
},
cli.StringFlag{
Name: "before",
Usage: "commit sha before the change",
},
cli.StringFlag{
Name: "after",
Usage: "commit sha after the change",
},
cli.StringFlag{
Name: "repository",
Usage: "repository name",
},
// TODO(bradrydzewski) these parameters should
// be defined globally for all plugin commands.
cli.StringFlag{
Name: "endpoint",
Usage: "plugin endpoint",
EnvVar: "DRONE_CONVERT_ENDPOINT",
},
cli.StringFlag{
Name: "secret",
Usage: "plugin secret",
EnvVar: "DRONE_CONVERT_SECRET",
},
cli.StringFlag{
Name: "ssl-skip-verify",
Usage: "plugin ssl verification disabled",
EnvVar: "DRONE_CONVERT_SKIP_VERIFY",
},
},
}
func convert(c *cli.Context) error {
slug := c.String("repository")
owner, name, _ := internal.ParseRepo(slug)
path := c.String("path")
if path == "" {
path = c.Args().First()
}
raw, err := ioutil.ReadFile(path)
if err != nil {
return err
}
req := &converter.Request{
Repo: drone.Repo{
Namespace: owner,
Name: name,
Slug: slug,
Config: path,
},
Build: drone.Build{
Ref: c.String("ref"),
Before: c.String("before"),
After: c.String("after"),
Source: c.String("source"),
Target: c.String("target"),
},
Config: drone.Config{
Data: string(raw),
},
}
client := converter.Client(
c.String("endpoint"),
c.String("secret"),
c.Bool("ssl-skip-verify"),
)
res, err := client.Convert(context.Background(), req)
if err != nil {
return err
}
switch {
case res == nil:
println(string(raw))
case res != nil:
println(res.Data)
}
return nil
}

24
drone/plugins/plugins.go Normal file

@ -0,0 +1,24 @@
package plugins
import (
"github.com/drone/drone-cli/drone/plugins/admit"
"github.com/drone/drone-cli/drone/plugins/config"
"github.com/drone/drone-cli/drone/plugins/convert"
"github.com/drone/drone-cli/drone/plugins/registry"
"github.com/drone/drone-cli/drone/plugins/secret"
"github.com/urfave/cli"
)
// Command exports the registry command set.
var Command = cli.Command{
Name: "plugins",
Usage: "plugin helper functions",
Subcommands: []cli.Command{
admit.Command,
config.Command,
convert.Command,
secret.Command,
registry.Command,
},
}

@ -0,0 +1,123 @@
package registry
import (
"context"
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/registry"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var registryListCmd = cli.Command{
Name: "list",
Usage: "list the registry credentials",
Action: registryList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "ref",
Usage: "git reference",
Value: "refs/heads/master",
},
cli.StringFlag{
Name: "source",
Usage: "source branch",
},
cli.StringFlag{
Name: "target",
Usage: "target branch",
},
cli.StringFlag{
Name: "before",
Usage: "commit sha before the change",
},
cli.StringFlag{
Name: "after",
Usage: "commit sha after the change",
},
cli.StringFlag{
Name: "event",
Usage: "build event",
},
cli.StringFlag{
Name: "repo",
Usage: "repository name",
},
// TODO(bradrydzewski) these parameters should
// be defined globally for all plugin commands.
cli.StringFlag{
Name: "endpoint",
Usage: "plugin endpoint",
EnvVar: "DRONE_REGISTRY_ENDPOINT",
},
cli.StringFlag{
Name: "secret",
Usage: "plugin secret",
EnvVar: "DRONE_REGISTRY_SECRET",
},
cli.StringFlag{
Name: "ssl-skip-verify",
Usage: "plugin ssl verification disabled",
EnvVar: "DRONE_REGISTRY_VERIFY",
},
cli.StringFlag{
Name: "format",
Value: tmplList,
},
},
}
func registryList(c *cli.Context) error {
slug := c.String("repo")
owner, name, _ := internal.ParseRepo(slug)
repo := drone.Repo{
Namespace: owner,
Name: name,
Slug: slug,
}
build := drone.Build{
Ref: c.String("ref"),
Before: c.String("before"),
After: c.String("after"),
Source: c.String("source"),
Target: c.String("target"),
Event: c.String("event"),
}
req := &registry.Request{
Repo: repo,
Build: build,
}
client := registry.Client(
c.String("endpoint"),
c.String("secret"),
c.Bool("ssl-skip-verify"),
)
list, err := client.List(context.Background(), req)
if err != nil {
return err
}
format := c.String("format") + "\n"
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, item := range list {
tmpl.Execute(os.Stdout, item)
}
return nil
}
var tmplList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Username: {{ .Username }}
Password: {{ .Password }}
`

@ -5,12 +5,8 @@ import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "registry",
Usage: "manage registries",
Usage: "registry plugin helpers",
Subcommands: []cli.Command{
registryCreateCmd,
registryDeleteCmd,
registryUpdateCmd,
registryInfoCmd,
registryListCmd,
},
}

112
drone/plugins/secret/get.go Normal file

@ -0,0 +1,112 @@
package secret
import (
"context"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/secret"
"github.com/urfave/cli"
)
var secretFindCmd = cli.Command{
Name: "get",
Usage: "get the named secret",
ArgsUsage: "secret",
Action: secretFind,
Flags: []cli.Flag{
cli.StringFlag{
Name: "ref",
Usage: "git reference",
Value: "refs/heads/master",
},
cli.StringFlag{
Name: "source",
Usage: "source branch",
},
cli.StringFlag{
Name: "target",
Usage: "target branch",
},
cli.StringFlag{
Name: "before",
Usage: "commit sha before the change",
},
cli.StringFlag{
Name: "after",
Usage: "commit sha after the change",
},
cli.StringFlag{
Name: "event",
Usage: "build event",
},
cli.StringFlag{
Name: "repo",
Usage: "repository name",
},
// TODO(bradrydzewski) these parameters should
// be defined globally for all plugin commands.
cli.StringFlag{
Name: "endpoint",
Usage: "plugin endpoint",
EnvVar: "DRONE_SECRET_ENDPOINT",
},
cli.StringFlag{
Name: "secret",
Usage: "plugin secret",
EnvVar: "DRONE_SECRET_SECRET",
},
cli.StringFlag{
Name: "ssl-skip-verify",
Usage: "plugin ssl verification disabled",
EnvVar: "DRONE_SECRET_VERIFY",
},
},
}
func secretFind(c *cli.Context) error {
path := c.Args().First()
key := c.Args().Get(1)
slug := c.String("repo")
owner, name, err := internal.ParseRepo(slug)
if err != nil {
return err
}
repo := drone.Repo{
Namespace: owner,
Name: name,
Slug: slug,
}
build := drone.Build{
Ref: c.String("ref"),
Before: c.String("before"),
After: c.String("after"),
Source: c.String("source"),
Target: c.String("target"),
Event: c.String("event"),
}
req := &secret.Request{
Path: path,
Name: key,
Repo: repo,
Build: build,
}
client := secret.Client(
c.String("endpoint"),
c.String("secret"),
c.Bool("ssl-skip-verify"),
)
res, err := client.Find(context.Background(), req)
if err != nil {
return err
}
println(res.Data)
return nil
}

@ -0,0 +1,12 @@
package secret
import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "secret",
Usage: "secret plugin helpers",
Subcommands: []cli.Command{
secretFindCmd,
},
}

14
drone/queue/queue.go Normal file

@ -0,0 +1,14 @@
package queue
import "github.com/urfave/cli"
// Command exports the queue command set.
var Command = cli.Command{
Name: "queue",
Usage: "queue operations",
Subcommands: []cli.Command{
queueListCmd,
queuePauseCmd,
queueResumeCmd,
},
}

59
drone/queue/queue_list.go Normal file

@ -0,0 +1,59 @@
package queue
import (
"fmt"
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var queueListCmd = cli.Command{
Name: "ls",
Usage: "list queue items",
Action: queueList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplStage,
},
},
}
func queueList(c *cli.Context) (err error) {
client, err := internal.NewClient(c)
if err != nil {
return err
}
builds, err := client.Queue()
if err != nil {
return err
}
if len(builds) == 0 {
fmt.Println("there are no pending or running builds")
return nil
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, build := range builds {
tmpl.Execute(os.Stdout, build)
}
return nil
}
var tmplStage = "\x1b[33mitem #{{ .ID }} \x1b[0m" + `
Status: {{ .Status }}
Machine: {{ .Machine }}
OS: {{ .OS }}
Arch: {{ .Arch }}
Variant: {{ .Variant }}
Version: {{ .Kernel }}
`

@ -0,0 +1,20 @@
package queue
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var queuePauseCmd = cli.Command{
Name: "pause",
Usage: "pause queue operations",
Action: queuePause,
}
func queuePause(c *cli.Context) (err error) {
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.QueuePause()
}

@ -0,0 +1,20 @@
package queue
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var queueResumeCmd = cli.Command{
Name: "resume",
Usage: "resume queue operations",
Action: queueResume,
}
func queueResume(c *cli.Context) (err error) {
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.QueueResume()
}

@ -1,75 +0,0 @@
package registry
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var registryCreateCmd = cli.Command{
Name: "add",
Usage: "adds a registry",
ArgsUsage: "[repo/name]",
Action: registryCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "username",
Usage: "registry username",
},
cli.StringFlag{
Name: "password",
Usage: "registry password",
},
},
}
func registryCreate(c *cli.Context) error {
var (
hostname = c.String("hostname")
username = c.String("username")
password = c.String("password")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry := &drone.Registry{
Address: hostname,
Username: username,
Password: password,
}
if strings.HasPrefix(registry.Password, "@") {
path := strings.TrimPrefix(registry.Password, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
registry.Password = string(out)
}
_, err = client.RegistryCreate(owner, name, registry)
if err != nil {
return err
}
return nil
}

@ -1,62 +0,0 @@
package registry
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var registryInfoCmd = cli.Command{
Name: "info",
Usage: "display registry info",
ArgsUsage: "[repo/name]",
Action: registryInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRegistryList,
Hidden: true,
},
},
}
func registryInfo(c *cli.Context) error {
var (
hostname = c.String("hostname")
reponame = c.String("repository")
format = c.String("format") + "\n"
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry, err := client.Registry(owner, name, hostname)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, registry)
}

@ -1,65 +0,0 @@
package registry
import (
"html/template"
"os"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var registryListCmd = cli.Command{
Name: "ls",
Usage: "list registries",
ArgsUsage: "[repo/name]",
Action: registryList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRegistryList,
Hidden: true,
},
},
}
func registryList(c *cli.Context) error {
var (
format = c.String("format") + "\n"
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
list, err := client.RegistryList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
}
for _, registry := range list {
tmpl.Execute(os.Stdout, registry)
}
return nil
}
// template for build list information
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Username: {{ .Username }}
Email: {{ .Email }}
`

@ -1,44 +0,0 @@
package registry
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var registryDeleteCmd = cli.Command{
Name: "rm",
Usage: "remove a registry",
ArgsUsage: "[repo/name]",
Action: registryDelete,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
},
}
func registryDelete(c *cli.Context) error {
var (
hostname = c.String("hostname")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.RegistryDelete(owner, name, hostname)
}

@ -1,75 +0,0 @@
package registry
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var registryUpdateCmd = cli.Command{
Name: "update",
Usage: "update a registry",
ArgsUsage: "[repo/name]",
Action: registryUpdate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "username",
Usage: "registry username",
},
cli.StringFlag{
Name: "password",
Usage: "registry password",
},
},
}
func registryUpdate(c *cli.Context) error {
var (
hostname = c.String("hostname")
username = c.String("username")
password = c.String("password")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry := &drone.Registry{
Address: hostname,
Username: username,
Password: password,
}
if strings.HasPrefix(registry.Password, "@") {
path := strings.TrimPrefix(registry.Password, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
registry.Password = string(out)
}
_, err = client.RegistryUpdate(owner, name, registry)
if err != nil {
return err
}
return nil
}

@ -8,8 +8,8 @@ import (
)
var repoAddCmd = cli.Command{
Name: "add",
Usage: "add a repository",
Name: "enable",
Usage: "enable a repository",
ArgsUsage: "<repo/name>",
Action: repoAdd,
}
@ -26,7 +26,7 @@ func repoAdd(c *cli.Context) error {
return err
}
if _, err := client.RepoPost(owner, name); err != nil {
if _, err := client.RepoEnable(owner, name); err != nil {
return err
}
fmt.Printf("Successfully activated repository %s/%s\n", owner, name)

@ -5,6 +5,7 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -39,7 +40,7 @@ func repoInfo(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format"))
if err != nil {
return err
}
@ -47,13 +48,12 @@ func repoInfo(c *cli.Context) error {
}
// template for repo information
var tmplRepoInfo = `Owner: {{ .Owner }}
var tmplRepoInfo = `Owner: {{ .Namespace }}
Repo: {{ .Name }}
Type: {{ .Kind }}
Config: {{ .Config }}
Visibility: {{ .Visibility }}
Private: {{ .IsPrivate }}
Trusted: {{ .IsTrusted }}
Gated: {{ .IsGated }}
Remote: {{ .Clone }}
Private: {{ .Private }}
Trusted: {{ .Trusted }}
Protected: {{ .Protected }}
Remote: {{ .HTTPURL }}
`

@ -5,6 +5,7 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -23,6 +24,10 @@ var repoListCmd = cli.Command{
Name: "org",
Usage: "filter by organization",
},
cli.BoolFlag{
Name: "active",
Usage: "filter active repositories only",
},
},
}
@ -37,14 +42,17 @@ func repoList(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
org := c.String("org")
org, active := c.String("org"), c.Bool("active")
for _, repo := range repos {
if org != "" && org != repo.Owner {
if org != "" && org != repo.Namespace {
continue
}
if !repo.Active && active {
continue
}
tmpl.Execute(os.Stdout, repo)
@ -53,4 +61,4 @@ func repoList(c *cli.Context) error {
}
// template for repository list items
var tmplRepoList = `{{ .FullName }}`
var tmplRepoList = `{{ .Slug }}`

@ -9,8 +9,8 @@ import (
)
var repoRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a repository",
Name: "disable",
Usage: "disable a repository",
ArgsUsage: "<repo/name>",
Action: repoRemove,
}
@ -27,7 +27,7 @@ func repoRemove(c *cli.Context) error {
return err
}
if err := client.RepoDel(owner, name); err != nil {
if err := client.RepoDisable(owner, name); err != nil {
return err
}
fmt.Printf("Successfully removed repository %s/%s\n", owner, name)

@ -5,6 +5,7 @@ import (
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
@ -28,21 +29,17 @@ func repoSync(c *cli.Context) error {
return err
}
repos, err := client.RepoListOpts(true, true)
repos, err := client.RepoListSync()
if err != nil || len(repos) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
org := c.String("org")
for _, repo := range repos {
if org != "" && org != repo.Owner {
continue
}
tmpl.Execute(os.Stdout, repo)
}
return nil

@ -21,8 +21,8 @@ var repoUpdateCmd = cli.Command{
Usage: "repository is trusted",
},
cli.BoolFlag{
Name: "gated",
Usage: "repository is gated",
Name: "protected",
Usage: "repository is protected",
},
cli.DurationFlag{
Name: "timeout",
@ -32,6 +32,22 @@ var repoUpdateCmd = cli.Command{
Name: "visibility",
Usage: "repository visibility",
},
cli.BoolFlag{
Name: "ignore-forks",
Usage: "ignore forks",
},
cli.BoolFlag{
Name: "ignore-pull-requests",
Usage: "ignore pull requests",
},
cli.BoolFlag{
Name: "auto-cancel-pull-requests",
Usage: "automatically cancel pending pull request builds",
},
cli.BoolFlag{
Name: "auto-cancel-pushes",
Usage: "automatically cancel pending push builds",
},
cli.StringFlag{
Name: "config",
Usage: "repository configuration path (e.g. .drone.yml)",
@ -64,17 +80,21 @@ func repoUpdate(c *cli.Context) error {
config = c.String("config")
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
protected = c.Bool("protected")
ignoreForks = c.Bool("ignore-forks")
ignorePulls = c.Bool("ignore-pull-requests")
cancelPulls = c.Bool("auto-cancel-pull-requests")
cancelPush = c.Bool("auto-cancel-pushes")
buildCounter = c.Int("build-counter")
unsafe = c.Bool("unsafe")
)
patch := new(drone.RepoPatch)
if c.IsSet("trusted") {
patch.IsTrusted = &trusted
patch.Trusted = &trusted
}
if c.IsSet("gated") {
patch.IsGated = &gated
if c.IsSet("protected") {
patch.Protected = &protected
}
if c.IsSet("timeout") {
v := int64(timeout / time.Minute)
@ -83,6 +103,18 @@ func repoUpdate(c *cli.Context) error {
if c.IsSet("config") {
patch.Config = &config
}
if c.IsSet("ignore-forks") {
patch.IgnoreForks = &ignoreForks
}
if c.IsSet("ignore-pull-requests") {
patch.IgnorePulls = &ignorePulls
}
if c.IsSet("auto-cancel-pull-requests") {
patch.CancelPulls = &cancelPulls
}
if c.IsSet("auto-cancel-pushes") {
patch.CancelPush = &cancelPush
}
if c.IsSet("visibility") {
switch visibility {
case "public", "private", "internal":
@ -93,10 +125,10 @@ func repoUpdate(c *cli.Context) error {
fmt.Printf("Setting the build counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed")
}
if c.IsSet("build-counter") && unsafe {
patch.BuildCounter = &buildCounter
patch.Counter = &buildCounter
}
if _, err := client.RepoPatch(owner, name, patch); err != nil {
if _, err := client.RepoUpdate(owner, name, patch); err != nil {
return err
}
fmt.Printf("Successfully updated repository %s/%s\n", owner, name)

@ -25,16 +25,16 @@ var secretCreateCmd = cli.Command{
Usage: "secret name",
},
cli.StringFlag{
Name: "value",
Name: "data",
Usage: "secret value",
},
cli.StringSliceFlag{
Name: "event",
Usage: "secret limited to these events",
cli.BoolFlag{
Name: "allow-pull-request",
Usage: "permit read access to pull requests",
},
cli.StringSliceFlag{
Name: "image",
Usage: "secret limited to these images",
cli.BoolFlag{
Name: "allow-push-on-pull-request",
Usage: "permit write access to pull requests (e.g. allow docker push)",
},
},
}
@ -54,27 +54,19 @@ func secretCreate(c *cli.Context) error {
}
secret := &drone.Secret{
Name: c.String("name"),
Value: c.String("value"),
Images: c.StringSlice("image"),
Events: c.StringSlice("event"),
Data: c.String("data"),
PullRequest: c.Bool("allow-pull-request"),
PullRequestPush: c.Bool("allow-push-on-pull-request"),
}
if len(secret.Events) == 0 {
secret.Events = defaultSecretEvents
}
if strings.HasPrefix(secret.Value, "@") {
path := strings.TrimPrefix(secret.Value, "@")
if strings.HasPrefix(secret.Data, "@") {
path := strings.TrimPrefix(secret.Data, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Value = string(out)
secret.Data = string(out)
}
_, err = client.SecretCreate(owner, name, secret)
return err
}
var defaultSecretEvents = []string{
drone.EventPush,
drone.EventTag,
drone.EventDeploy,
}

@ -5,9 +5,9 @@ import (
"html/template"
"os"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var secretInfoCmd = cli.Command{
@ -28,7 +28,6 @@ var secretInfoCmd = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
Hidden: true,
},
},
}
@ -57,7 +56,7 @@ func secretInfo(c *cli.Context) error {
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}

@ -3,11 +3,10 @@ package secret
import (
"html/template"
"os"
"strings"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var secretListCmd = cli.Command{
@ -24,7 +23,6 @@ var secretListCmd = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
Hidden: true,
},
},
}
@ -49,28 +47,18 @@ func secretList(c *cli.Context) error {
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(format)
if err != nil {
return err
}
for _, registry := range list {
tmpl.Execute(os.Stdout, registry)
for _, secret := range list {
tmpl.Execute(os.Stdout, secret)
}
return nil
}
// template for secret list items
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
Events: {{ list .Events }}
{{- if .Images }}
Images: {{ list .Images }}
{{- else }}
Images: <any>
{{- end }}
Pull Request Read: {{ .PullRequest }}
Pull Request Write: {{ .PullRequestPush }}
`
var secretFuncMap = template.FuncMap{
"list": func(s []string) string {
return strings.Join(s, ", ")
},
}

@ -25,16 +25,16 @@ var secretUpdateCmd = cli.Command{
Usage: "secret name",
},
cli.StringFlag{
Name: "value",
Name: "data",
Usage: "secret value",
},
cli.StringSliceFlag{
Name: "event",
Usage: "secret limited to these events",
cli.BoolFlag{
Name: "allow-pull-request",
Usage: "permit read access to pull requests",
},
cli.StringSliceFlag{
Name: "image",
Usage: "secret limited to these images",
cli.BoolFlag{
Name: "allow-push-on-pull-request",
Usage: "permit write access to pull requests (e.g. allow docker push)",
},
},
}
@ -54,17 +54,17 @@ func secretUpdate(c *cli.Context) error {
}
secret := &drone.Secret{
Name: c.String("name"),
Value: c.String("value"),
Images: c.StringSlice("image"),
Events: c.StringSlice("event"),
Data: c.String("data"),
PullRequest: c.Bool("allow-pull-request"),
PullRequestPush: c.Bool("allow-push-on-pull-request"),
}
if strings.HasPrefix(secret.Value, "@") {
path := strings.TrimPrefix(secret.Value, "@")
if strings.HasPrefix(secret.Data, "@") {
path := strings.TrimPrefix(secret.Data, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Value = string(out)
secret.Data = string(out)
}
_, err = client.SecretUpdate(owner, name, secret)
return err

@ -4,21 +4,20 @@ import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var serverCreateCmd = cli.Command{
Name: "create",
Usage: "crate a new server",
Usage: "create a new server",
Action: serverCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplServerCreate,
Hidden: true,
},
},
}
@ -34,7 +33,7 @@ func serverCreate(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}

@ -5,9 +5,9 @@ import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var serverDestroyCmd = cli.Command{
@ -20,7 +20,10 @@ var serverDestroyCmd = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplServerDestroy,
Hidden: true,
},
cli.BoolFlag{
Name: "force",
Usage: "force destroy",
},
},
}
@ -36,7 +39,7 @@ func serverDestroy(c *cli.Context) error {
return fmt.Errorf("Missing or invalid server name")
}
err = client.ServerDelete(name)
err = client.ServerDelete(name, c.Bool("force"))
if err != nil {
return err
}
@ -46,7 +49,7 @@ func serverDestroy(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}

@ -9,10 +9,10 @@ import (
"path"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var serverEnvCmd = cli.Command{
@ -108,7 +108,7 @@ func serverEnv(c *cli.Context) error {
})
}
var shellT = template.Must(template.New("_").Parse(`
var shellT = template.Must(template.New("_").Funcs(funcmap.Funcs).Parse(`
{{- if eq .Shell "fish" -}}
sex -x DOCKER_TLS "1";
set -x DOCKER_TLS_VERIFY "";

@ -5,9 +5,9 @@ import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var serverInfoCmd = cli.Command{
@ -20,7 +20,6 @@ var serverInfoCmd = cli.Command{
Name: "format",
Usage: "format output",
Value: tmplServerInfo,
Hidden: true,
},
},
}
@ -41,7 +40,7 @@ func serverInfo(c *cli.Context) error {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}

@ -8,10 +8,10 @@ import (
"time"
"github.com/docker/go-units"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/drone/funcmap"
"github.com/urfave/cli"
)
var serverListCmd = cli.Command{
@ -20,23 +20,26 @@ var serverListCmd = cli.Command{
ArgsUsage: " ",
Action: serverList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "s, state",
Usage: "filter by state",
},
cli.BoolFlag{
Name: "a",
Name: "a, all",
Usage: "include stopped servers",
},
cli.BoolFlag{
Name: "l",
Name: "l, long",
Usage: "list in long format",
},
cli.BoolTFlag{
Name: "H",
Usage: "include columne headers",
Name: "H, headers",
Usage: "include column headers",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplServerList,
Hidden: true,
},
cli.BoolFlag{
Name: "la",
@ -50,6 +53,7 @@ func serverList(c *cli.Context) error {
if err != nil {
return err
}
s := c.String("s")
a := c.Bool("a")
l := c.Bool("l")
h := c.BoolT("H")
@ -65,11 +69,11 @@ func serverList(c *cli.Context) error {
}
if l && h {
printLong(servers, a, h)
printLong(servers, s, a, h)
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.String("format") + "\n")
if err != nil {
return err
}
@ -78,12 +82,17 @@ func serverList(c *cli.Context) error {
if !a && server.State == "stopped" {
continue
}
if s != "" && s != server.State {
continue
}
tmpl.Execute(os.Stdout, server)
}
return nil
}
func printLong(servers []*drone.Server, a, h bool) {
func printLong(servers []*drone.Server, s string, a, h bool) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
if h {
fmt.Fprintln(w, "Name\tAddress\tState\tCreated")
@ -92,6 +101,9 @@ func printLong(servers []*drone.Server, a, h bool) {
if !a && server.State == "stopped" {
continue
}
if s != "" && s != server.State {
continue
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\n",
server.Name,
server.Address,

63
drone/sign/sign.go Normal file

@ -0,0 +1,63 @@
package sign
import (
"fmt"
"io/ioutil"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-yaml/yaml/signer"
"github.com/urfave/cli"
)
// Command exports the sign command.
var Command = cli.Command{
Name: "sign",
Usage: "sign the yaml file",
ArgsUsage: "<source>",
Action: format,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "save",
Usage: "save result to source",
},
},
}
func format(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
path := c.Args().Get(1)
if path == "" {
path = ".drone.yml"
}
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
hmac, err := client.Sign(owner, name, string(data))
if err != nil {
return err
}
if c.Bool("save") == false {
fmt.Println(hmac)
return nil
}
data, err = signer.WriteTo(data, hmac)
if err != nil {
return err
}
return ioutil.WriteFile(path, data, 0644)
}

@ -0,0 +1,8 @@
def docker(repo):
return {
'name': 'docker',
'image': 'plugins/docker',
'settings': {
'repo': repo,
},
}

@ -0,0 +1,33 @@
# cd drone/starlark/samples
# drone script --source pipeline.py --stdout
load('docker.py', 'docker')
def build(version):
return {
'name': 'build',
'image': 'golang:%s' % version,
'commands': [
'go build',
'go test',
]
}
def main(ctx):
if ctx['build']['message'].find('[skip build]'):
return {
'kind': 'pipeline',
'name': 'publish_only',
'steps': [
docker('octocat/hello-world'),
],
}
return {
'kind': 'pipeline',
'name': 'build_and_publish',
'steps': [
build('1.11'),
build('1.12'),
docker('octocat/hello-world'),
],
}

317
drone/starlark/starlark.go Normal file

@ -0,0 +1,317 @@
package starlark
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"github.com/drone/drone-yaml/yaml"
"github.com/drone/drone-yaml/yaml/pretty"
"github.com/urfave/cli"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
)
// Command exports the jsonnet command.
var Command = cli.Command{
Name: "starlark",
Usage: "generate .drone.yml from starlark",
ArgsUsage: "[path/to/.drone.star]",
Action: func(c *cli.Context) {
if err := generate(c); err != nil {
if err, ok := err.(*starlark.EvalError); ok {
log.Fatalf("starlark evaluation error:\n%s", err.Backtrace())
}
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "source",
Usage: "Source file",
Value: ".drone.star",
},
cli.StringFlag{
Name: "target",
Usage: "target file",
Value: ".drone.yml",
},
cli.BoolTFlag{
Name: "format",
Usage: "Write output as formatted YAML",
},
cli.BoolFlag{
Name: "stdout",
Usage: "Write output to stdout",
},
//
// Drone Parameters
//
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
},
cli.StringFlag{
Name: "repo.namespace",
Usage: "repository namespace",
},
cli.StringFlag{
Name: "repo.slug",
Usage: "repository slug",
},
cli.StringFlag{
Name: "build.event",
Usage: "build event",
Value: "push",
},
cli.StringFlag{
Name: "build.branch",
Usage: "build branch",
Value: "master",
},
cli.StringFlag{
Name: "build.source",
Usage: "build source branch",
Value: "master",
},
cli.StringFlag{
Name: "build.target",
Usage: "build target branch",
Value: "master",
},
cli.StringFlag{
Name: "build.ref",
Usage: "build ref",
Value: "refs/heads/master",
},
cli.StringFlag{
Name: "build.commit",
Usage: "build commit sha",
},
cli.StringFlag{
Name: "build.message",
Usage: "build commit message",
},
},
}
func generate(c *cli.Context) error {
source := c.String("source")
target := c.String("target")
data, err := ioutil.ReadFile(source)
if err != nil {
return err
}
thread := &starlark.Thread{
Name: "drone",
Print: func(_ *starlark.Thread, msg string) { fmt.Println(msg) },
Load: makeLoad(),
}
globals, err := starlark.ExecFile(thread, source, data, nil)
if err != nil {
return err
}
mainVal, ok := globals["main"]
if !ok {
return fmt.Errorf("no main function found")
}
main, ok := mainVal.(starlark.Callable)
if !ok {
return fmt.Errorf("main must be a function")
}
// TODO this needs to be flushed out.
repo := starlark.StringDict{
"name": starlark.String(c.String("repo.name")),
"namespace": starlark.String(c.String("repo.namespace")),
"slug": starlark.String(c.String("repo.slug")),
}
build := starlark.StringDict{
"event": starlark.String(c.String("build.event")),
"branch": starlark.String(c.String("build.branch")),
"source": starlark.String(c.String("build.source_branch")),
"target": starlark.String(c.String("build.target_branch")),
"ref": starlark.String(c.String("build.ref")),
"commit": starlark.String(c.String("build.commit")),
"message": starlark.String(c.String("build.message")),
}
args := starlark.Tuple([]starlark.Value{
starlarkstruct.FromStringDict(
starlark.String("context"),
starlark.StringDict{
"repo": starlarkstruct.FromStringDict(starlark.String("repo"), repo),
"build": starlarkstruct.FromStringDict(starlark.String("build"), build),
},
),
})
mainVal, err = starlark.Call(thread, main, args, nil)
if err != nil {
return err
}
buf := new(bytes.Buffer)
switch v := mainVal.(type) {
case *starlark.List:
for i := 0; i < v.Len(); i++ {
item := v.Index(i)
buf.WriteString("---\n")
err = writeJSON(buf, item)
if err != nil {
return err
}
buf.WriteString("\n")
}
case *starlark.Dict:
buf.WriteString("---\n")
err = writeJSON(buf, v)
if err != nil {
return err
}
default:
return fmt.Errorf("invalid return type (got a %s)", mainVal.Type())
}
// if the user disables pretty printing, the yaml is printed
// to the console or written to the file in json format.
if c.BoolT("format") == false {
if c.Bool("stdout") {
io.Copy(os.Stdout, buf)
return nil
}
return ioutil.WriteFile(target, buf.Bytes(), 0644)
}
manifest, err := yaml.Parse(buf)
if err != nil {
return err
}
buf.Reset()
pretty.Print(buf, manifest)
// the user can optionally write the yaml to stdout. This
// is useful for debugging purposes without mutating an
// existing file.
if c.Bool("stdout") {
io.Copy(os.Stdout, buf)
return nil
}
return ioutil.WriteFile(target, buf.Bytes(), 0644)
}
// Adapted from skycfg:
// https://github.com/stripe/skycfg/blob/eaa524101c2a0807c13ed5d2e52576fefc146ec3/internal/go/skycfg/json_write.go#L45
func writeJSON(out *bytes.Buffer, v starlark.Value) error {
if marshaler, ok := v.(json.Marshaler); ok {
jsonData, err := marshaler.MarshalJSON()
if err != nil {
return err
}
out.Write(jsonData)
return nil
}
switch v := v.(type) {
case starlark.NoneType:
out.WriteString("null")
case starlark.Bool:
fmt.Fprintf(out, "%t", v)
case starlark.Int:
out.WriteString(v.String())
case starlark.Float:
fmt.Fprintf(out, "%g", v)
case starlark.String:
s := string(v)
if goQuoteIsSafe(s) {
fmt.Fprintf(out, "%q", s)
} else {
// vanishingly rare for text strings
data, _ := json.Marshal(s)
out.Write(data)
}
case starlark.Indexable: // Tuple, List
out.WriteByte('[')
for i, n := 0, starlark.Len(v); i < n; i++ {
if i > 0 {
out.WriteString(", ")
}
if err := writeJSON(out, v.Index(i)); err != nil {
return err
}
}
out.WriteByte(']')
case *starlark.Dict:
out.WriteByte('{')
for i, itemPair := range v.Items() {
key := itemPair[0]
value := itemPair[1]
if i > 0 {
out.WriteString(", ")
}
if err := writeJSON(out, key); err != nil {
return err
}
out.WriteString(": ")
if err := writeJSON(out, value); err != nil {
return err
}
}
out.WriteByte('}')
default:
return fmt.Errorf("TypeError: value %s (type `%s') can't be converted to JSON.", v.String(), v.Type())
}
return nil
}
func goQuoteIsSafe(s string) bool {
for _, r := range s {
// JSON doesn't like Go's \xHH escapes for ASCII control codes,
// nor its \UHHHHHHHH escapes for runes >16 bits.
if r < 0x20 || r >= 0x10000 {
return false
}
}
return true
}
// https://github.com/google/starlark-go/blob/4eb76950c5f02ec5bcfd3ca898231a6543942fd9/repl/repl.go#L175
func makeLoad() func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
type entry struct {
globals starlark.StringDict
err error
}
var cache = make(map[string]*entry)
return func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
e, ok := cache[module]
if e == nil {
if ok {
// request for package whose loading is in progress
return nil, fmt.Errorf("cycle in load graph")
}
// Add a placeholder to indicate "load in progress".
cache[module] = nil
// Load it.
thread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
globals, err := starlark.ExecFile(thread, module, nil, nil)
e = &entry{globals, err}
// Update the cache.
cache[module] = e
}
return e.globals, e.err
}
}

Some files were not shown because too many files have changed in this diff Show More