mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-22 02:19:25 +00:00
Move Plugins to a /plugin Directory
This commit is contained in:
@@ -8,12 +8,12 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v1"
|
||||
|
||||
"github.com/drone/drone/plugin/deploy"
|
||||
"github.com/drone/drone/plugin/notify"
|
||||
"github.com/drone/drone/plugin/publish"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
"github.com/drone/drone/shared/build/git"
|
||||
"github.com/drone/drone/shared/build/repo"
|
||||
"github.com/drone/drone/shared/deploy"
|
||||
"github.com/drone/drone/shared/notify"
|
||||
"github.com/drone/drone/shared/publish"
|
||||
)
|
||||
|
||||
func ParseBuild(data string, params map[string]string) (*Build, error) {
|
||||
|
@@ -1,12 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type AppFog struct {
|
||||
}
|
||||
|
||||
func (a *AppFog) Write(f *buildfile.Buildfile) {
|
||||
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Bash struct {
|
||||
Script []string `yaml:"script,omitempty"`
|
||||
Command string `yaml:"command,omitempty"`
|
||||
}
|
||||
|
||||
func (g *Bash) Write(f *buildfile.Buildfile) {
|
||||
g.Script = append(g.Script, g.Command)
|
||||
|
||||
for _, cmd := range g.Script {
|
||||
f.WriteCmd(cmd)
|
||||
}
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
|
||||
"gopkg.in/yaml.v1"
|
||||
)
|
||||
|
||||
// emulate Build struct
|
||||
type buildWithBash struct {
|
||||
Deploy *Deploy `yaml:"deploy,omitempty"`
|
||||
}
|
||||
|
||||
var sampleYmlWithBash = `
|
||||
deploy:
|
||||
bash:
|
||||
command: 'echo bash_deployed'
|
||||
`
|
||||
|
||||
var sampleYmlWithScript = `
|
||||
deploy:
|
||||
bash:
|
||||
script:
|
||||
- ./bin/deploy.sh
|
||||
- ./bin/check.sh
|
||||
`
|
||||
|
||||
var sampleYmlWithBashAndScript = `
|
||||
deploy:
|
||||
bash:
|
||||
command: ./bin/some_cmd.sh
|
||||
script:
|
||||
- ./bin/deploy.sh
|
||||
- ./bin/check.sh
|
||||
`
|
||||
|
||||
func setUpWithBash(input string) (string, error) {
|
||||
var buildStruct buildWithBash
|
||||
err := yaml.Unmarshal([]byte(input), &buildStruct)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bf := buildfile.New()
|
||||
buildStruct.Deploy.Write(bf)
|
||||
return bf.String(), err
|
||||
}
|
||||
|
||||
func TestBashDeployment(t *testing.T) {
|
||||
bscr, err := setUpWithBash(sampleYmlWithBash)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "echo bash_deployed") {
|
||||
t.Error("Expect script to contains bash command")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBashDeploymentWithScript(t *testing.T) {
|
||||
bscr, err := setUpWithBash(sampleYmlWithScript)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "./bin/deploy.sh") {
|
||||
t.Error("Expect script to contains bash script")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "./bin/check.sh") {
|
||||
t.Error("Expect script to contains bash script")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBashDeploymentWithBashAndScript(t *testing.T) {
|
||||
bscr, err := setUpWithBash(sampleYmlWithBashAndScript)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "./bin/deploy.sh") {
|
||||
t.Error("Expect script to contains bash script")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "./bin/check.sh") {
|
||||
t.Error("Expect script to contains bash script")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "./bin/some_cmd.sh") {
|
||||
t.Error("Expect script to contains bash script")
|
||||
}
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type CloudControl struct {
|
||||
}
|
||||
|
||||
func (c *CloudControl) Write(f *buildfile.Buildfile) {
|
||||
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type CloudFoundry struct {
|
||||
Target string `yaml:"target,omitempty"`
|
||||
Username string `yaml:"username,omitempty"`
|
||||
Password string `yaml:"password,omitempty"`
|
||||
Org string `yaml:"org,omitempty"`
|
||||
Space string `yaml:"space,omitempty"`
|
||||
|
||||
App string `yaml:"app,omitempty"`
|
||||
}
|
||||
|
||||
func (cf *CloudFoundry) Write(f *buildfile.Buildfile) {
|
||||
downloadCmd := "curl -sLO http://go-cli.s3-website-us-east-1.amazonaws.com/releases/latest/cf-cli_amd64.deb"
|
||||
installCmd := "dpkg -i cf-cli_amd64.deb 1> /dev/null 2> /dev/null"
|
||||
|
||||
// download and install the cf tool
|
||||
f.WriteCmdSilent(fmt.Sprintf("[ -f /usr/bin/sudo ] && sudo %s || %s", downloadCmd, downloadCmd))
|
||||
f.WriteCmdSilent(fmt.Sprintf("[ -f /usr/bin/sudo ] && sudo %s || %s", installCmd, installCmd))
|
||||
|
||||
// login
|
||||
loginCmd := "cf login -a %s -u %s -p %s"
|
||||
|
||||
organization := cf.Org
|
||||
if organization != "" {
|
||||
loginCmd += fmt.Sprintf(" -o %s", organization)
|
||||
}
|
||||
|
||||
space := cf.Space
|
||||
if space != "" {
|
||||
loginCmd += fmt.Sprintf(" -s %s", space)
|
||||
}
|
||||
|
||||
f.WriteCmdSilent(fmt.Sprintf(loginCmd, cf.Target, cf.Username, cf.Password))
|
||||
|
||||
// push app
|
||||
pushCmd := "cf push %s"
|
||||
f.WriteCmd(fmt.Sprintf(pushCmd, cf.App))
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
|
||||
"gopkg.in/yaml.v1"
|
||||
)
|
||||
|
||||
// emulate Build struct
|
||||
type DeployToCF struct {
|
||||
Deploy *Deploy `yaml:"deploy,omitempty"`
|
||||
}
|
||||
|
||||
var sampleYmlBasic = `
|
||||
deploy:
|
||||
cloudfoundry:
|
||||
target: https://api.example.com
|
||||
username: foo
|
||||
password: bar
|
||||
`
|
||||
|
||||
var sampleYmlWithOrg = `
|
||||
deploy:
|
||||
cloudfoundry:
|
||||
target: https://api.example.com
|
||||
username: foo
|
||||
password: bar
|
||||
org: custom-org
|
||||
`
|
||||
|
||||
var sampleYmlWithSpace = `
|
||||
deploy:
|
||||
cloudfoundry:
|
||||
target: https://api.example.com
|
||||
username: foo
|
||||
password: bar
|
||||
org: custom-org
|
||||
space: dev
|
||||
`
|
||||
|
||||
var sampleYmlWithAppName = `
|
||||
deploy:
|
||||
cloudfoundry:
|
||||
target: https://api.example.com
|
||||
username: foo
|
||||
password: bar
|
||||
app: test-app
|
||||
`
|
||||
|
||||
func setUpWithCF(input string) (string, error) {
|
||||
var buildStruct DeployToCF
|
||||
err := yaml.Unmarshal([]byte(input), &buildStruct)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bf := buildfile.New()
|
||||
buildStruct.Deploy.Write(bf)
|
||||
return bf.String(), err
|
||||
}
|
||||
|
||||
func TestCloudFoundryToolInstall(t *testing.T) {
|
||||
bscr, err := setUpWithCF(sampleYmlBasic)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "curl -sLO http://go-cli.s3-website-us-east-1.amazonaws.com/releases/latest/cf-cli_amd64.deb") {
|
||||
t.Error("Expect script to contain download command")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "dpkg -i cf-cli_amd64.deb") {
|
||||
t.Error("Expect script to contain install command")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFoundryDeployment(t *testing.T) {
|
||||
bscr, err := setUpWithCF(sampleYmlBasic)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "cf login -a https://api.example.com -u foo -p bar") {
|
||||
t.Error("Expect login script to contain username and password")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "cf push") {
|
||||
t.Error("Expect script to contain push")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFoundryDeploymentWithOrg(t *testing.T) {
|
||||
bscr, err := setUpWithCF(sampleYmlWithOrg)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "cf login -a https://api.example.com -u foo -p bar -o custom-org") {
|
||||
t.Error("Expect login script to contain organization")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFoundryDeploymentWithSpace(t *testing.T) {
|
||||
bscr, err := setUpWithCF(sampleYmlWithSpace)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "cf login -a https://api.example.com -u foo -p bar -o custom-org -s dev") {
|
||||
t.Error("Expect login script to contain space")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudFoundryDeploymentWithApp(t *testing.T) {
|
||||
bscr, err := setUpWithCF(sampleYmlWithAppName)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "cf push test-app") {
|
||||
t.Error("Expect login script to contain app name")
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
// Deploy stores the configuration details
|
||||
// for deploying build artifacts when
|
||||
// a Build has succeeded
|
||||
type Deploy struct {
|
||||
AppFog *AppFog `yaml:"appfog,omitempty"`
|
||||
CloudControl *CloudControl `yaml:"cloudcontrol,omitempty"`
|
||||
CloudFoundry *CloudFoundry `yaml:"cloudfoundry,omitempty"`
|
||||
EngineYard *EngineYard `yaml:"engineyard,omitempty"`
|
||||
Git *Git `yaml:"git,omitempty"`
|
||||
Heroku *Heroku `yaml:"heroku,omitempty"`
|
||||
Modulus *Modulus `yaml:"modulus,omitempty"`
|
||||
Nodejitsu *Nodejitsu `yaml:"nodejitsu,omitempty"`
|
||||
Openshift *Openshift `yaml:"openshift,omitempty"`
|
||||
SSH *SSH `yaml:"ssh,omitempty"`
|
||||
Tsuru *Tsuru `yaml:"tsuru,omitempty"`
|
||||
Bash *Bash `yaml:"bash,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Deploy) Write(f *buildfile.Buildfile) {
|
||||
if d.AppFog != nil {
|
||||
d.AppFog.Write(f)
|
||||
}
|
||||
if d.CloudControl != nil {
|
||||
d.CloudControl.Write(f)
|
||||
}
|
||||
if d.CloudFoundry != nil {
|
||||
d.CloudFoundry.Write(f)
|
||||
}
|
||||
if d.EngineYard != nil {
|
||||
d.EngineYard.Write(f)
|
||||
}
|
||||
if d.Git != nil {
|
||||
d.Git.Write(f)
|
||||
}
|
||||
if d.Heroku != nil {
|
||||
d.Heroku.Write(f)
|
||||
}
|
||||
if d.Modulus != nil {
|
||||
d.Modulus.Write(f)
|
||||
}
|
||||
if d.Nodejitsu != nil {
|
||||
d.Nodejitsu.Write(f)
|
||||
}
|
||||
if d.Openshift != nil {
|
||||
d.Openshift.Write(f)
|
||||
}
|
||||
if d.SSH != nil {
|
||||
d.SSH.Write(f)
|
||||
}
|
||||
if d.Tsuru != nil {
|
||||
d.Tsuru.Write(f)
|
||||
}
|
||||
if d.Bash != nil {
|
||||
d.Bash.Write(f)
|
||||
}
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type EngineYard struct {
|
||||
}
|
||||
|
||||
func (e *EngineYard) Write(f *buildfile.Buildfile) {
|
||||
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Git struct {
|
||||
Target string `yaml:"target,omitempty"`
|
||||
Force bool `yaml:"force,omitempty"`
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (g *Git) Write(f *buildfile.Buildfile) {
|
||||
// get the current commit hash
|
||||
f.WriteCmdSilent("COMMIT=$(git rev-parse HEAD)")
|
||||
|
||||
// set the git user and email based on the individual
|
||||
// that made the commit.
|
||||
f.WriteCmdSilent("git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')")
|
||||
f.WriteCmdSilent("git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')")
|
||||
|
||||
// add target as a git remote
|
||||
f.WriteCmd(fmt.Sprintf("git remote add deploy %s", g.Target))
|
||||
|
||||
destinationBranch := g.Branch
|
||||
if destinationBranch == "" {
|
||||
destinationBranch = "master"
|
||||
}
|
||||
|
||||
switch g.Force {
|
||||
case true:
|
||||
// this is useful when the there are artifacts generated
|
||||
// by the build script, such as less files converted to css,
|
||||
// that need to be deployed to git remote.
|
||||
f.WriteCmd(fmt.Sprintf("git add -A"))
|
||||
f.WriteCmd(fmt.Sprintf("git commit -m 'add build artifacts'"))
|
||||
f.WriteCmd(fmt.Sprintf("git push deploy $COMMIT:%s --force", destinationBranch))
|
||||
case false:
|
||||
// otherwise we just do a standard git push
|
||||
f.WriteCmd(fmt.Sprintf("git push deploy $COMMIT:%s", destinationBranch))
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Heroku struct {
|
||||
App string `yaml:"app,omitempty"`
|
||||
Force bool `yaml:"force,omitempty"`
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (h *Heroku) Write(f *buildfile.Buildfile) {
|
||||
// get the current commit hash
|
||||
f.WriteCmdSilent("COMMIT=$(git rev-parse HEAD)")
|
||||
|
||||
// set the git user and email based on the individual
|
||||
// that made the commit.
|
||||
f.WriteCmdSilent("git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')")
|
||||
f.WriteCmdSilent("git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')")
|
||||
|
||||
// add heroku as a git remote
|
||||
f.WriteCmd(fmt.Sprintf("git remote add heroku git@heroku.com:%s.git", h.App))
|
||||
|
||||
switch h.Force {
|
||||
case true:
|
||||
// this is useful when the there are artifacts generated
|
||||
// by the build script, such as less files converted to css,
|
||||
// that need to be deployed to Heroku.
|
||||
f.WriteCmd(fmt.Sprintf("git add -A"))
|
||||
f.WriteCmd(fmt.Sprintf("git commit -m 'adding build artifacts'"))
|
||||
f.WriteCmd(fmt.Sprintf("git push heroku $COMMIT:master --force"))
|
||||
case false:
|
||||
// otherwise we just do a standard git push
|
||||
f.WriteCmd(fmt.Sprintf("git push heroku $COMMIT:master"))
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Modulus struct {
|
||||
Project string `yaml:"project,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Modulus) Write(f *buildfile.Buildfile) {
|
||||
f.WriteEnv("MODULUS_TOKEN", m.Token)
|
||||
|
||||
// Install the Modulus command line interface then deploy the configured
|
||||
// project.
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] || npm install -g modulus")
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo npm install -g modulus")
|
||||
f.WriteCmd(fmt.Sprintf("modulus deploy -p '%s'", m.Project))
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Nodejitsu struct {
|
||||
App string `yaml:"app,omitempty"`
|
||||
User string `yaml:"user,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
}
|
||||
|
||||
func (n *Nodejitsu) Write(f *buildfile.Buildfile) {
|
||||
f.WriteEnv("username", n.User)
|
||||
f.WriteEnv("apiToken", n.Token)
|
||||
|
||||
// Install the jitsu command line interface then
|
||||
// deploy the configured app.
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] || npm install -g jitsu")
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo npm install -g jitsu")
|
||||
f.WriteCmd("jitsu deploy")
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Openshift struct {
|
||||
}
|
||||
|
||||
func (o *Openshift) Write(f *buildfile.Buildfile) {
|
||||
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
// SSH struct holds configuration data for deployment
|
||||
// via ssh, deployment done by scp-ing file(s) listed
|
||||
// in artifacts to the target host, and then run cmd
|
||||
// remotely.
|
||||
// It is assumed that the target host already
|
||||
// add this repo public key in the host's `authorized_hosts`
|
||||
// file. And the private key is already copied to `.ssh/id_rsa`
|
||||
// inside the build container. No further check will be done.
|
||||
type SSH struct {
|
||||
|
||||
// Target is the deployment host in this format
|
||||
// user@hostname:/full/path <PORT>
|
||||
//
|
||||
// PORT may be omitted if its default to port 22.
|
||||
Target string `yaml:"target,omitempty"`
|
||||
|
||||
// Artifacts is a list of files/dirs to be deployed
|
||||
// to the target host. If artifacts list more than one file
|
||||
// it will be compressed into a single tar.gz file.
|
||||
// if artifacts contain:
|
||||
// - GITARCHIVE
|
||||
//
|
||||
// other file listed in artifacts will be ignored, instead, we will
|
||||
// create git archive from the current revision and deploy that file
|
||||
// alone.
|
||||
// If you need to deploy the git archive along with some other files,
|
||||
// please use build script to create the git archive, and then list
|
||||
// the archive name here with the other files.
|
||||
Artifacts []string `yaml:"artifacts,omitempty"`
|
||||
|
||||
// Cmd is a single command executed at target host after the artifacts
|
||||
// is deployed.
|
||||
Cmd string `yaml:"cmd,omitempty"`
|
||||
}
|
||||
|
||||
// Write down the buildfile
|
||||
func (s *SSH) Write(f *buildfile.Buildfile) {
|
||||
host := strings.SplitN(s.Target, " ", 2)
|
||||
if len(host) == 1 {
|
||||
host = append(host, "22")
|
||||
}
|
||||
if _, err := strconv.Atoi(host[1]); err != nil {
|
||||
host[1] = "22"
|
||||
}
|
||||
|
||||
// Is artifact created?
|
||||
artifact := false
|
||||
|
||||
for _, a := range s.Artifacts {
|
||||
if a == "GITARCHIVE" {
|
||||
artifact = createGitArchive(f)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !artifact {
|
||||
if len(s.Artifacts) > 1 {
|
||||
artifact = compress(f, s.Artifacts)
|
||||
} else if len(s.Artifacts) == 1 {
|
||||
f.WriteEnv("ARTIFACT", s.Artifacts[0])
|
||||
artifact = true
|
||||
}
|
||||
}
|
||||
|
||||
if artifact {
|
||||
scpCmd := "scp -o StrictHostKeyChecking=no -P %s -r ${ARTIFACT} %s"
|
||||
f.WriteCmd(fmt.Sprintf(scpCmd, host[1], host[0]))
|
||||
}
|
||||
|
||||
if len(s.Cmd) > 0 {
|
||||
sshCmd := "ssh -o StrictHostKeyChecking=no -p %s %s %s"
|
||||
f.WriteCmd(fmt.Sprintf(sshCmd, host[1], strings.SplitN(host[0], ":", 2)[0], s.Cmd))
|
||||
}
|
||||
}
|
||||
|
||||
func createGitArchive(f *buildfile.Buildfile) bool {
|
||||
f.WriteEnv("COMMIT", "$(git rev-parse HEAD)")
|
||||
f.WriteEnv("ARTIFACT", "${PWD##*/}-${COMMIT}.tar.gz")
|
||||
f.WriteCmdSilent("git archive --format=tar.gz --prefix=${PWD##*/}/ ${COMMIT} > ${ARTIFACT}")
|
||||
return true
|
||||
}
|
||||
|
||||
func compress(f *buildfile.Buildfile, files []string) bool {
|
||||
cmd := "tar -cf ${ARTIFACT} %s"
|
||||
f.WriteEnv("ARTIFACT", "${PWD##*/}.tar.gz")
|
||||
f.WriteCmdSilent(fmt.Sprintf(cmd, strings.Join(files, " ")))
|
||||
return true
|
||||
}
|
@@ -1,129 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
|
||||
"gopkg.in/yaml.v1"
|
||||
)
|
||||
|
||||
// emulate Build struct
|
||||
type build struct {
|
||||
Deploy *Deploy `yaml:"deploy,omitempty"`
|
||||
}
|
||||
|
||||
var sampleYml = `
|
||||
deploy:
|
||||
ssh:
|
||||
target: user@test.example.com
|
||||
cmd: /opt/bin/redeploy.sh
|
||||
`
|
||||
|
||||
var sampleYml1 = `
|
||||
deploy:
|
||||
ssh:
|
||||
target: user@test.example.com:/srv/app/location 2212
|
||||
artifacts:
|
||||
- build.result
|
||||
cmd: /opt/bin/redeploy.sh
|
||||
`
|
||||
|
||||
var sampleYml2 = `
|
||||
deploy:
|
||||
ssh:
|
||||
target: user@test.example.com:/srv/app/location 2212
|
||||
artifacts:
|
||||
- build.result
|
||||
- config/file
|
||||
cmd: /opt/bin/redeploy.sh
|
||||
`
|
||||
|
||||
var sampleYml3 = `
|
||||
deploy:
|
||||
ssh:
|
||||
target: user@test.example.com:/srv/app/location 2212
|
||||
artifacts:
|
||||
- GITARCHIVE
|
||||
cmd: /opt/bin/redeploy.sh
|
||||
`
|
||||
|
||||
func setUp(input string) (string, error) {
|
||||
var buildStruct build
|
||||
err := yaml.Unmarshal([]byte(input), &buildStruct)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bf := buildfile.New()
|
||||
buildStruct.Deploy.Write(bf)
|
||||
return bf.String(), err
|
||||
}
|
||||
|
||||
func TestSSHNoArtifact(t *testing.T) {
|
||||
bscr, err := setUp(sampleYml)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if strings.Contains(bscr, `scp`) {
|
||||
t.Error("Expect script not to contains scp command")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "ssh -o StrictHostKeyChecking=no -p 22 user@test.example.com /opt/bin/redeploy.sh") {
|
||||
t.Error("Expect script to contains ssh command")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHOneArtifact(t *testing.T) {
|
||||
bscr, err := setUp(sampleYml1)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "ARTIFACT=build.result") {
|
||||
t.Error("Expect script to contains artifact")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "scp -o StrictHostKeyChecking=no -P 2212 -r ${ARTIFACT} user@test.example.com:/srv/app/location") {
|
||||
t.Errorf("Expect script to contains scp command, got:\n%s", bscr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHMultiArtifact(t *testing.T) {
|
||||
bscr, err := setUp(sampleYml2)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "ARTIFACT=${PWD##*/}.tar.gz") {
|
||||
t.Errorf("Expect script to contains artifact")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "tar -cf ${ARTIFACT} build.result config/file") {
|
||||
t.Errorf("Expect script to contains tar command. got: %s\n", bscr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHGitArchive(t *testing.T) {
|
||||
bscr, err := setUp(sampleYml3)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal deploy script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "COMMIT=$(git rev-parse HEAD)") {
|
||||
t.Errorf("Expect script to contains commit ref")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "ARTIFACT=${PWD##*/}-${COMMIT}.tar.gz") {
|
||||
t.Errorf("Expect script to contains artifact")
|
||||
}
|
||||
|
||||
if strings.Contains(bscr, "=GITARCHIVE") {
|
||||
t.Errorf("Doesn't expect script to contains GITARCHIVE literals")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "git archive --format=tar.gz --prefix=${PWD##*/}/ ${COMMIT} > ${ARTIFACT}") {
|
||||
t.Errorf("Expect script to run git archive")
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Tsuru struct {
|
||||
Force bool `yaml:"force,omitempty"`
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
Remote string `yaml:"remote,omitempty"`
|
||||
}
|
||||
|
||||
func (h *Tsuru) Write(f *buildfile.Buildfile) {
|
||||
// get the current commit hash
|
||||
f.WriteCmdSilent("COMMIT=$(git rev-parse HEAD)")
|
||||
|
||||
// set the git user and email based on the individual
|
||||
// that made the commit.
|
||||
f.WriteCmdSilent("git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')")
|
||||
f.WriteCmdSilent("git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')")
|
||||
|
||||
// add tsuru as a git remote
|
||||
f.WriteCmd(fmt.Sprintf("git remote add tsuru %s", h.Remote))
|
||||
|
||||
switch h.Force {
|
||||
case true:
|
||||
// this is useful when the there are artifacts generated
|
||||
// by the build script, such as less files converted to css,
|
||||
// that need to be deployed to Tsuru.
|
||||
f.WriteCmd(fmt.Sprintf("git add -A"))
|
||||
f.WriteCmd(fmt.Sprintf("git commit -m 'adding build artifacts'"))
|
||||
f.WriteCmd(fmt.Sprintf("git push tsuru $COMMIT:master --force"))
|
||||
case false:
|
||||
// otherwise we just do a standard git push
|
||||
f.WriteCmd(fmt.Sprintf("git push tsuru $COMMIT:master"))
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
package notify
|
||||
|
||||
//import "github.com/drone/drone/pkg/mail"
|
||||
|
||||
type Email struct {
|
||||
Recipients []string `yaml:"recipients,omitempty"`
|
||||
Success string `yaml:"on_success"`
|
||||
Failure string `yaml:"on_failure"`
|
||||
}
|
||||
|
||||
// Send will send an email, either success or failure,
|
||||
// based on the Commit Status.
|
||||
func (e *Email) Send(context *Context) error {
|
||||
switch {
|
||||
case context.Commit.Status == "Success" && e.Success != "never":
|
||||
return e.sendSuccess(context)
|
||||
case context.Commit.Status == "Failure" && e.Failure != "never":
|
||||
return e.sendFailure(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendFailure sends email notifications to the list of
|
||||
// recipients indicating the build failed.
|
||||
func (e *Email) sendFailure(context *Context) error {
|
||||
// loop through and email recipients
|
||||
//for _, email := range e.Recipients {
|
||||
//if err := mail.SendFailure(context.Repo.Name, context.Commit.HashShort(), email, context); err != nil {
|
||||
// return err
|
||||
//}
|
||||
//}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendSuccess sends email notifications to the list of
|
||||
// recipients indicating the build was a success.
|
||||
func (e *Email) sendSuccess(context *Context) error {
|
||||
// loop through and email recipients
|
||||
//for _, email := range e.Recipients {
|
||||
// if err := mail.SendSuccess(context.Repo.Name, context.Commit.HashShort(), email, context); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
return nil
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/andybons/hipchat"
|
||||
)
|
||||
|
||||
const (
|
||||
startedMessage = "Building %s, commit %s, author %s"
|
||||
successMessage = "<b>Success</b> %s, commit %s, author %s"
|
||||
failureMessage = "<b>Failed</b> %s, commit %s, author %s"
|
||||
)
|
||||
|
||||
type Hipchat struct {
|
||||
Room string `yaml:"room,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
Started bool `yaml:"on_started,omitempty"`
|
||||
Success bool `yaml:"on_success,omitempty"`
|
||||
Failure bool `yaml:"on_failure,omitempty"`
|
||||
}
|
||||
|
||||
func (h *Hipchat) Send(context *Context) error {
|
||||
switch {
|
||||
case context.Commit.Status == "Started" && h.Started:
|
||||
return h.sendStarted(context)
|
||||
case context.Commit.Status == "Success" && h.Success:
|
||||
return h.sendSuccess(context)
|
||||
case context.Commit.Status == "Failure" && h.Failure:
|
||||
return h.sendFailure(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hipchat) sendStarted(context *Context) error {
|
||||
msg := fmt.Sprintf(startedMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
return h.send(hipchat.ColorYellow, hipchat.FormatHTML, msg)
|
||||
}
|
||||
|
||||
func (h *Hipchat) sendFailure(context *Context) error {
|
||||
msg := fmt.Sprintf(failureMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
return h.send(hipchat.ColorRed, hipchat.FormatHTML, msg)
|
||||
}
|
||||
|
||||
func (h *Hipchat) sendSuccess(context *Context) error {
|
||||
msg := fmt.Sprintf(successMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
return h.send(hipchat.ColorGreen, hipchat.FormatHTML, msg)
|
||||
}
|
||||
|
||||
// helper function to send Hipchat requests
|
||||
func (h *Hipchat) send(color, format, message string) error {
|
||||
c := hipchat.Client{AuthToken: h.Token}
|
||||
req := hipchat.MessageRequest{
|
||||
RoomId: h.Room,
|
||||
From: "Drone",
|
||||
Message: message,
|
||||
Color: color,
|
||||
MessageFormat: format,
|
||||
Notify: true,
|
||||
}
|
||||
|
||||
return c.PostMessage(req)
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
irc "github.com/fluffle/goirc/client"
|
||||
)
|
||||
|
||||
const (
|
||||
ircStartedMessage = "Building: %s, commit %s, author %s"
|
||||
ircSuccessMessage = "Success: %s, commit %s, author %s"
|
||||
ircFailureMessage = "Failed: %s, commit %s, author %s"
|
||||
)
|
||||
|
||||
type IRC struct {
|
||||
Channel string `yaml:"channel,omitempty"`
|
||||
Nick string `yaml:"nick,omitempty"`
|
||||
Server string `yaml:"server,omitempty"`
|
||||
Started bool `yaml:"on_started,omitempty"`
|
||||
Success bool `yaml:"on_success,omitempty"`
|
||||
Failure bool `yaml:"on_failure,omitempty"`
|
||||
SSL bool `yaml:"ssl,omitempty"`
|
||||
ClientStarted bool
|
||||
Client *irc.Conn
|
||||
}
|
||||
|
||||
func (i *IRC) Connect() {
|
||||
c := irc.SimpleClient(i.Nick)
|
||||
c.SSL = i.SSL
|
||||
connected := make(chan bool)
|
||||
c.AddHandler(irc.CONNECTED,
|
||||
func(conn *irc.Conn, line *irc.Line) {
|
||||
conn.Join(i.Channel)
|
||||
connected <- true
|
||||
})
|
||||
c.Connect(i.Server)
|
||||
<-connected
|
||||
i.ClientStarted = true
|
||||
i.Client = c
|
||||
}
|
||||
|
||||
func (i *IRC) Send(context *Context) error {
|
||||
switch {
|
||||
case context.Commit.Status == "Started" && i.Started:
|
||||
return i.sendStarted(context)
|
||||
case context.Commit.Status == "Success" && i.Success:
|
||||
return i.sendSuccess(context)
|
||||
case context.Commit.Status == "Failure" && i.Failure:
|
||||
return i.sendFailure(context)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IRC) sendStarted(context *Context) error {
|
||||
msg := fmt.Sprintf(ircStartedMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
i.send(i.Channel, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IRC) sendFailure(context *Context) error {
|
||||
msg := fmt.Sprintf(ircFailureMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
i.send(i.Channel, msg)
|
||||
if i.ClientStarted {
|
||||
i.Client.Quit()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IRC) sendSuccess(context *Context) error {
|
||||
msg := fmt.Sprintf(ircSuccessMessage, context.Repo.Name, context.Commit.ShaShort(), context.Commit.Author)
|
||||
i.send(i.Channel, msg)
|
||||
if i.ClientStarted {
|
||||
i.Client.Quit()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IRC) send(channel string, message string) error {
|
||||
if !i.ClientStarted {
|
||||
i.Connect()
|
||||
}
|
||||
i.Client.Notice(channel, message)
|
||||
return nil
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/server/resource/commit"
|
||||
"github.com/drone/drone/server/resource/repo"
|
||||
"github.com/drone/drone/server/resource/user"
|
||||
)
|
||||
|
||||
// Context represents the context of an
|
||||
// in-progress build request.
|
||||
type Context struct {
|
||||
// Global settings
|
||||
Host string
|
||||
|
||||
// User that owns the repository
|
||||
User *user.User
|
||||
|
||||
// Repository being built.
|
||||
Repo *repo.Repo
|
||||
|
||||
// Commit being built
|
||||
Commit *commit.Commit
|
||||
}
|
||||
|
||||
type Sender interface {
|
||||
Send(context *Context) error
|
||||
}
|
||||
|
||||
// Notification stores the configuration details
|
||||
// for notifying a user, or group of users,
|
||||
// when their Build has completed.
|
||||
type Notification struct {
|
||||
Email *Email `yaml:"email,omitempty"`
|
||||
Webhook *Webhook `yaml:"webhook,omitempty"`
|
||||
Hipchat *Hipchat `yaml:"hipchat,omitempty"`
|
||||
Irc *IRC `yaml:"irc,omitempty"`
|
||||
Slack *Slack `yaml:"slack,omitempty"`
|
||||
}
|
||||
|
||||
func (n *Notification) Send(context *Context) error {
|
||||
// send email notifications
|
||||
if n.Email != nil {
|
||||
n.Email.Send(context)
|
||||
}
|
||||
|
||||
// send email notifications
|
||||
if n.Webhook != nil {
|
||||
n.Webhook.Send(context)
|
||||
}
|
||||
|
||||
// send email notifications
|
||||
if n.Hipchat != nil {
|
||||
n.Hipchat.Send(context)
|
||||
}
|
||||
|
||||
// send irc notifications
|
||||
if n.Irc != nil {
|
||||
n.Irc.Send(context)
|
||||
}
|
||||
|
||||
// send slack notifications
|
||||
if n.Slack != nil {
|
||||
n.Slack.Send(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
slackEndpoint = "https://%s.slack.com/services/hooks/incoming-webhook?token=%s"
|
||||
slackStartedMessage = "*Building* %s, commit <%s|%s>, author %s"
|
||||
slackSuccessMessage = "*Success* %s, commit <%s|%s>, author %s"
|
||||
slackFailureMessage = "*Failed* %s, commit <%s|%s>, author %s"
|
||||
)
|
||||
|
||||
type Slack struct {
|
||||
Team string `yaml:"team,omitempty"`
|
||||
Channel string `yaml:"channel,omitempty"`
|
||||
Username string `yaml:"username,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
Started bool `yaml:"on_started,omitempty"`
|
||||
Success bool `yaml:"on_success,omitempty"`
|
||||
Failure bool `yaml:"on_failure,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Slack) Send(context *Context) error {
|
||||
switch {
|
||||
case context.Commit.Status == "Started" && s.Started:
|
||||
return s.sendStarted(context)
|
||||
case context.Commit.Status == "Success" && s.Success:
|
||||
return s.sendSuccess(context)
|
||||
case context.Commit.Status == "Failure" && s.Failure:
|
||||
return s.sendFailure(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBuildUrl(context *Context) string {
|
||||
return fmt.Sprintf("%s/%s/%s/%s/branch/%s/commit/%s", context.Host, context.Repo.Host, context.Repo.Owner, context.Repo.Name, context.Commit.Branch, context.Commit.Sha)
|
||||
}
|
||||
|
||||
func getMessage(context *Context, message string) string {
|
||||
url := getBuildUrl(context)
|
||||
return fmt.Sprintf(message, context.Repo.Name, url, context.Commit.ShaShort(), context.Commit.Author)
|
||||
}
|
||||
|
||||
func (s *Slack) sendStarted(context *Context) error {
|
||||
return s.send(getMessage(context, slackStartedMessage))
|
||||
}
|
||||
|
||||
func (s *Slack) sendSuccess(context *Context) error {
|
||||
return s.send(getMessage(context, slackSuccessMessage))
|
||||
}
|
||||
|
||||
func (s *Slack) sendFailure(context *Context) error {
|
||||
return s.send(getMessage(context, slackFailureMessage))
|
||||
}
|
||||
|
||||
// helper function to send HTTP requests
|
||||
func (s *Slack) send(msg string) error {
|
||||
// data will get posted in this format
|
||||
data := struct {
|
||||
Channel string `json:"channel"`
|
||||
Username string `json:"username"`
|
||||
Text string `json:"text"`
|
||||
}{s.Channel, s.Username, msg}
|
||||
|
||||
// data json encoded
|
||||
payload, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send payload
|
||||
url := fmt.Sprintf(slackEndpoint, s.Team, s.Token)
|
||||
go sendJson(url, payload)
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/server/resource/commit"
|
||||
"github.com/drone/drone/server/resource/repo"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_getBuildUrl(t *testing.T) {
|
||||
c := &Context{
|
||||
Host: "http://examplehost.com",
|
||||
Repo: &repo.Repo{
|
||||
Host: "examplegit.com",
|
||||
Owner: "owner",
|
||||
Name: "repo",
|
||||
},
|
||||
Commit: &commit.Commit{
|
||||
Sha: "abc",
|
||||
Branch: "example",
|
||||
},
|
||||
}
|
||||
expected := "http://examplehost.com/examplegit.com/owner/repo/branch/example/commit/abc"
|
||||
output := getBuildUrl(c)
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("Failed to build url. Expected: %s, got %s", expected, output)
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/server/resource/commit"
|
||||
"github.com/drone/drone/server/resource/repo"
|
||||
"github.com/drone/drone/server/resource/user"
|
||||
)
|
||||
|
||||
type Webhook struct {
|
||||
URL []string `yaml:"urls,omitempty"`
|
||||
Success bool `yaml:"on_success,omitempty"`
|
||||
Failure bool `yaml:"on_failure,omitempty"`
|
||||
}
|
||||
|
||||
func (w *Webhook) Send(context *Context) error {
|
||||
switch {
|
||||
case context.Commit.Status == "Success" && w.Success:
|
||||
return w.send(context)
|
||||
case context.Commit.Status == "Failure" && w.Failure:
|
||||
return w.send(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function to send HTTP requests
|
||||
func (w *Webhook) send(context *Context) error {
|
||||
// data will get posted in this format
|
||||
data := struct {
|
||||
Owner *user.User `json:"owner"`
|
||||
Repo *repo.Repo `json:"repository"`
|
||||
Commit *commit.Commit `json:"commit"`
|
||||
}{context.User, context.Repo, context.Commit}
|
||||
|
||||
// data json encoded
|
||||
payload, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// loop through and email recipients
|
||||
for _, url := range w.URL {
|
||||
go sendJson(url, payload)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper fuction to sent HTTP Post requests
|
||||
// with JSON data as the payload.
|
||||
func sendJson(url string, payload []byte) {
|
||||
buf := bytes.NewBuffer(payload)
|
||||
resp, err := http.Post(url, "application/json", buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
@@ -1 +0,0 @@
|
||||
package notify
|
@@ -1 +0,0 @@
|
||||
package publish
|
@@ -1 +0,0 @@
|
||||
package publish
|
@@ -1 +0,0 @@
|
||||
package publish
|
@@ -1 +0,0 @@
|
||||
package publish
|
@@ -1,73 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
// use npm trick instead of running npm adduser that requires stdin
|
||||
var npmLoginCmd = `
|
||||
cat <<EOF > ~/.npmrc
|
||||
_auth = $(echo "%s:%s" | tr -d "\r\n" | base64)
|
||||
email = %s
|
||||
EOF
|
||||
`
|
||||
|
||||
type NPM struct {
|
||||
// The Email address used by NPM to connect
|
||||
// and publish to a repository
|
||||
Email string `yaml:"email,omitempty"`
|
||||
|
||||
// The Username used by NPM to connect
|
||||
// and publish to a repository
|
||||
Username string `yaml:"username,omitempty"`
|
||||
|
||||
// The Password used by NPM to connect
|
||||
// and publish to a repository
|
||||
Password string `yaml:"password,omitempty"`
|
||||
|
||||
// Fails if the package name and version combination already
|
||||
// exists in the registry. Overwrites when the "--force" flag is set.
|
||||
Force bool `yaml:"force"`
|
||||
|
||||
// The registry URL of custom npm repository
|
||||
Registry string `yaml:"registry,omitempty"`
|
||||
|
||||
// A folder containing the package.json file
|
||||
Folder string `yaml:"folder,omitempty"`
|
||||
|
||||
// Registers the published package with the given tag
|
||||
Tag string `yaml:"tag,omitempty"`
|
||||
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (n *NPM) Write(f *buildfile.Buildfile) {
|
||||
|
||||
if len(n.Email) == 0 || len(n.Username) == 0 || len(n.Password) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
npmPublishCmd := "npm publish %s"
|
||||
|
||||
if n.Tag != "" {
|
||||
npmPublishCmd += fmt.Sprintf(" --tag %s", n.Tag)
|
||||
}
|
||||
|
||||
if n.Force {
|
||||
npmPublishCmd += " --force"
|
||||
}
|
||||
|
||||
f.WriteCmdSilent("echo 'publishing to NPM ...'")
|
||||
|
||||
// Login to registry
|
||||
f.WriteCmdSilent(fmt.Sprintf(npmLoginCmd, n.Username, n.Password, n.Email))
|
||||
|
||||
// Setup custom npm registry
|
||||
if n.Registry != "" {
|
||||
f.WriteCmdSilent(fmt.Sprintf("npm config set registry %s", n.Registry))
|
||||
}
|
||||
|
||||
f.WriteCmd(fmt.Sprintf(npmPublishCmd, n.Folder))
|
||||
}
|
@@ -1,91 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
|
||||
"gopkg.in/yaml.v1"
|
||||
)
|
||||
|
||||
// emulate Build struct
|
||||
type PublishToNPM struct {
|
||||
Publish *Publish `yaml:"publish,omitempty"`
|
||||
}
|
||||
|
||||
var sampleYml1 = `
|
||||
publish:
|
||||
npm:
|
||||
username: foo
|
||||
email: foo@example.com
|
||||
password: bar
|
||||
`
|
||||
|
||||
var sampleYml2 = `
|
||||
publish:
|
||||
npm:
|
||||
username: foo
|
||||
email: foo@example.com
|
||||
password: bar
|
||||
force: true
|
||||
`
|
||||
|
||||
var sampleYmlWithReg = `
|
||||
publish:
|
||||
npm:
|
||||
username: foo
|
||||
email: foo@example.com
|
||||
password: bar
|
||||
registry: https://npm.example.com/me/
|
||||
folder: my-project/node-app/
|
||||
tag: 1.2.3
|
||||
`
|
||||
|
||||
func setUpWithNPM(input string) (string, error) {
|
||||
var buildStruct PublishToNPM
|
||||
err := yaml.Unmarshal([]byte(input), &buildStruct)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bf := buildfile.New()
|
||||
buildStruct.Publish.Write(bf, nil)
|
||||
return bf.String(), err
|
||||
}
|
||||
|
||||
func TestNPMPublish(t *testing.T) {
|
||||
bscr, err := setUpWithNPM(sampleYml1)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal publish script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "npm publish") {
|
||||
t.Error("Expect script to contain install command")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNPMForcePublish(t *testing.T) {
|
||||
bscr, err := setUpWithNPM(sampleYml2)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal publish script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "npm publish --force") {
|
||||
t.Error("Expect script to contain install command")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNPMPublishRegistry(t *testing.T) {
|
||||
bscr, err := setUpWithNPM(sampleYmlWithReg)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't unmarshal publish script: %s", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "npm config set registry https://npm.example.com/me/") {
|
||||
t.Error("Expect script to contain npm config registry command")
|
||||
}
|
||||
|
||||
if !strings.Contains(bscr, "npm publish my-project/node-app/ --tag 1.2.3") {
|
||||
t.Error("Expect script to contain npm publish command")
|
||||
}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
package publish
|
@@ -1,38 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
"github.com/drone/drone/shared/build/repo"
|
||||
)
|
||||
|
||||
// Publish stores the configuration details
|
||||
// for publishing build artifacts when
|
||||
// a Build has succeeded
|
||||
type Publish struct {
|
||||
S3 *S3 `yaml:"s3,omitempty"`
|
||||
Swift *Swift `yaml:"swift,omitempty"`
|
||||
PyPI *PyPI `yaml:"pypi,omitempty"`
|
||||
NPM *NPM `yaml:"npm,omitempty"`
|
||||
}
|
||||
|
||||
func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
|
||||
// S3
|
||||
if p.S3 != nil && (len(p.S3.Branch) == 0 || (len(p.S3.Branch) > 0 && r.Branch == p.S3.Branch)) {
|
||||
p.S3.Write(f)
|
||||
}
|
||||
|
||||
// Swift
|
||||
if p.Swift != nil && (len(p.Swift.Branch) == 0 || (len(p.Swift.Branch) > 0 && r.Branch == p.Swift.Branch)) {
|
||||
p.Swift.Write(f)
|
||||
}
|
||||
|
||||
// PyPI
|
||||
if p.PyPI != nil && (len(p.PyPI.Branch) == 0 || (len(p.PyPI.Branch) > 0 && r.Branch == p.PyPI.Branch)) {
|
||||
p.PyPI.Write(f)
|
||||
}
|
||||
|
||||
// NPM
|
||||
if p.NPM != nil && (len(p.NPM.Branch) == 0 || (len(p.NPM.Branch) > 0 && r.Branch == p.NPM.Branch)) {
|
||||
p.NPM.Write(f)
|
||||
}
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
// set up the .pypirc file
|
||||
var pypirc = `
|
||||
cat <<EOF > $HOME/.pypirc
|
||||
[distutils]
|
||||
index-servers =
|
||||
%s
|
||||
|
||||
[%s]
|
||||
username:%s
|
||||
password:%s
|
||||
%s
|
||||
EOF`
|
||||
|
||||
var deployCmd = `
|
||||
if [ -n "$_PYPI_SETUP_PY" ]
|
||||
then
|
||||
python $_PYPI_SETUP_PY sdist %s upload -r %s
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "Deploy to PyPI failed - perhaps due to the version number not being incremented. Continuing..."
|
||||
fi
|
||||
else
|
||||
echo "Failed to find setup.py file"
|
||||
fi
|
||||
`
|
||||
|
||||
type PyPI struct {
|
||||
Username string `yaml:"username,omitempty"`
|
||||
Password string `yaml:"password,omitempty"`
|
||||
Formats []string `yaml:"formats,omitempty"`
|
||||
Repository string `yaml:"repository,omitempty"`
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PyPI) Write(f *buildfile.Buildfile) {
|
||||
var indexServer string
|
||||
var repository string
|
||||
|
||||
if len(p.Username) == 0 || len(p.Password) == 0 {
|
||||
// nothing to do if the config is fundamentally flawed
|
||||
return
|
||||
}
|
||||
|
||||
// Handle the setting a custom pypi server/repository
|
||||
if len(p.Repository) == 0 {
|
||||
indexServer = "pypi"
|
||||
repository = ""
|
||||
} else {
|
||||
indexServer = "custom"
|
||||
repository = fmt.Sprintf("repository:%s", p.Repository)
|
||||
}
|
||||
|
||||
f.WriteCmdSilent("echo 'publishing to PyPI...'")
|
||||
|
||||
// find the setup.py file
|
||||
f.WriteCmdSilent("_PYPI_SETUP_PY=$(find . -name 'setup.py')")
|
||||
|
||||
// build the .pypirc file that pypi expects
|
||||
f.WriteCmdSilent(fmt.Sprintf(pypirc, indexServer, indexServer, p.Username, p.Password, repository))
|
||||
formatStr := p.BuildFormatStr()
|
||||
|
||||
// if we found the setup.py file use it to deploy
|
||||
f.WriteCmdSilent(fmt.Sprintf(deployCmd, formatStr, indexServer))
|
||||
}
|
||||
|
||||
func (p *PyPI) BuildFormatStr() string {
|
||||
if len(p.Formats) == 0 {
|
||||
// the format parameter is optional - if it's not here,
|
||||
// omit the format string completely.
|
||||
return ""
|
||||
}
|
||||
fmtStr := "--formats "
|
||||
for i := range p.Formats {
|
||||
fmtStr += p.Formats[i] + ","
|
||||
}
|
||||
return fmtStr[:len(fmtStr)-1]
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type S3 struct {
|
||||
Key string `yaml:"access_key,omitempty"`
|
||||
Secret string `yaml:"secret_key,omitempty"`
|
||||
Bucket string `yaml:"bucket,omitempty"`
|
||||
|
||||
// us-east-1
|
||||
// us-west-1
|
||||
// us-west-2
|
||||
// eu-west-1
|
||||
// ap-southeast-1
|
||||
// ap-southeast-2
|
||||
// ap-northeast-1
|
||||
// sa-east-1
|
||||
Region string `yaml:"region,omitempty"`
|
||||
|
||||
// Indicates the files ACL, which should be one
|
||||
// of the following:
|
||||
// private
|
||||
// public-read
|
||||
// public-read-write
|
||||
// authenticated-read
|
||||
// bucket-owner-read
|
||||
// bucket-owner-full-control
|
||||
Access string `yaml:"acl,omitempty"`
|
||||
|
||||
// Copies the files from the specified directory.
|
||||
// Regexp matching will apply to match multiple
|
||||
// files
|
||||
//
|
||||
// Examples:
|
||||
// /path/to/file
|
||||
// /path/to/*.txt
|
||||
// /path/to/*/*.txt
|
||||
// /path/to/**
|
||||
Source string `yaml:"source,omitempty"`
|
||||
Target string `yaml:"target,omitempty"`
|
||||
|
||||
// Recursive uploads
|
||||
Recursive bool `yaml:"recursive"`
|
||||
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (s *S3) Write(f *buildfile.Buildfile) {
|
||||
|
||||
// skip if AWS key or SECRET are empty. A good example for this would
|
||||
// be forks building a project. S3 might be configured in the source
|
||||
// repo, but not in the fork
|
||||
if len(s.Key) == 0 || len(s.Secret) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// debugging purposes so we can see if / where something is failing
|
||||
f.WriteCmdSilent("echo 'publishing to Amazon S3 ...'")
|
||||
|
||||
// install the AWS cli using PIP
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] || pip install awscli 1> /dev/null 2> /dev/null")
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo pip install awscli 1> /dev/null 2> /dev/null")
|
||||
|
||||
f.WriteEnv("AWS_ACCESS_KEY_ID", s.Key)
|
||||
f.WriteEnv("AWS_SECRET_ACCESS_KEY", s.Secret)
|
||||
|
||||
// make sure a default region is set
|
||||
if len(s.Region) == 0 {
|
||||
s.Region = "us-east-1"
|
||||
}
|
||||
|
||||
// make sure a default access is set
|
||||
// let's be conservative and assume private
|
||||
if len(s.Access) == 0 {
|
||||
s.Access = "private"
|
||||
}
|
||||
|
||||
// if the target starts with a "/" we need
|
||||
// to remove it, otherwise we might adding
|
||||
// a 3rd slash to s3://
|
||||
if strings.HasPrefix(s.Target, "/") {
|
||||
s.Target = s.Target[1:]
|
||||
}
|
||||
|
||||
switch s.Recursive {
|
||||
case true:
|
||||
f.WriteCmd(fmt.Sprintf(`aws s3 cp %s s3://%s/%s --recursive --acl %s --region %s`, s.Source, s.Bucket, s.Target, s.Access, s.Region))
|
||||
case false:
|
||||
f.WriteCmd(fmt.Sprintf(`aws s3 cp %s s3://%s/%s --acl %s --region %s`, s.Source, s.Bucket, s.Target, s.Access, s.Region))
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
package publish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/shared/build/buildfile"
|
||||
)
|
||||
|
||||
type Swift struct {
|
||||
// Username for authentication
|
||||
Username string `yaml:"username,omitempty"`
|
||||
|
||||
// Password for authentication
|
||||
// With Rackspace this is usually an API Key
|
||||
Password string `yaml:"password,omitempty"`
|
||||
|
||||
// Container to upload files to
|
||||
Container string `yaml:"container,omitempty"`
|
||||
|
||||
// Base API version URL to authenticate against
|
||||
// Rackspace: https://identity.api.rackspacecloud.com/v2.0
|
||||
AuthURL string `yaml:"auth_url,omitempty"`
|
||||
|
||||
// Region to communicate with, in a generic OpenStack install
|
||||
// this may be RegionOne
|
||||
Region string `yaml:"region,omitempty"`
|
||||
|
||||
// Source file or directory to upload, if source is a directory,
|
||||
// upload the contents of the directory
|
||||
Source string `yaml:"source,omitempty"`
|
||||
|
||||
// Destination to write the file(s) to. Should contain the full
|
||||
// object name if source is a file
|
||||
Target string `yaml:"target,omitempty"`
|
||||
|
||||
Branch string `yaml:"branch,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Swift) Write(f *buildfile.Buildfile) {
|
||||
var target string
|
||||
// All options are required, so ensure they are present
|
||||
if len(s.Username) == 0 || len(s.Password) == 0 || len(s.AuthURL) == 0 || len(s.Region) == 0 || len(s.Source) == 0 || len(s.Container) == 0 {
|
||||
f.WriteCmdSilent(`echo "Swift: Missing argument(s)"`)
|
||||
return
|
||||
}
|
||||
|
||||
// If a target was provided, prefix it with a /
|
||||
if len(s.Target) > 0 {
|
||||
target = fmt.Sprintf("/%s", strings.TrimPrefix(s.Target, "/"))
|
||||
}
|
||||
|
||||
// debugging purposes so we can see if / where something is failing
|
||||
f.WriteCmdSilent(`echo "Swift: Publishing..."`)
|
||||
|
||||
// install swiftly using PIP
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] || pip install swiftly 1> /dev/null 2> /dev/null")
|
||||
f.WriteCmdSilent("[ -f /usr/bin/sudo ] && sudo pip install swiftly 1> /dev/null 2> /dev/null")
|
||||
|
||||
// Write out environment variables
|
||||
f.WriteEnv("SWIFTLY_AUTH_URL", s.AuthURL)
|
||||
f.WriteEnv("SWIFTLY_AUTH_USER", s.Username)
|
||||
f.WriteEnv("SWIFTLY_AUTH_KEY", s.Password)
|
||||
f.WriteEnv("SWIFTLY_REGION", s.Region)
|
||||
|
||||
f.WriteCmd(fmt.Sprintf(`swiftly put -i %s %s%s`, s.Source, s.Container, target))
|
||||
}
|
@@ -1,147 +0,0 @@
|
||||
package bitbucket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/shared/remote"
|
||||
"github.com/drone/drone/shared/util/httputil"
|
||||
"github.com/drone/go-bitbucket/bitbucket"
|
||||
"github.com/drone/go-bitbucket/oauth1"
|
||||
)
|
||||
|
||||
type Bitbucket struct {
|
||||
URL string `json:"url"` // https://bitbucket.org
|
||||
API string `json:"api"` // https://api.bitbucket.org
|
||||
Client string `json:"client"`
|
||||
Secret string `json:"secret"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// GetName returns the name of this remote system.
|
||||
func (b *Bitbucket) GetName() string {
|
||||
return "bitbucket.org"
|
||||
}
|
||||
|
||||
// GetHost returns the url.Host of this remote system.
|
||||
func (b *Bitbucket) GetHost() (host string) {
|
||||
u, err := url.Parse(b.URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return u.Host
|
||||
}
|
||||
|
||||
// GetHook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func (b *Bitbucket) GetHook(r *http.Request) (*remote.Hook, error) {
|
||||
// get the payload from the request
|
||||
payload := r.FormValue("payload")
|
||||
|
||||
// parse the post-commit hook
|
||||
hook, err := bitbucket.ParseHook([]byte(payload))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// verify the payload has the minimum amount of required data.
|
||||
if hook.Repo == nil || hook.Commits == nil || len(hook.Commits) == 0 {
|
||||
return nil, fmt.Errorf("Invalid Bitbucket post-commit Hook. Missing Repo or Commit data.")
|
||||
}
|
||||
|
||||
return &remote.Hook{
|
||||
Owner: hook.Repo.Owner,
|
||||
Repo: hook.Repo.Name,
|
||||
Sha: hook.Commits[len(hook.Commits)-1].Hash,
|
||||
Branch: hook.Commits[len(hook.Commits)-1].Branch,
|
||||
Author: hook.Commits[len(hook.Commits)-1].Author,
|
||||
Timestamp: time.Now().UTC().String(),
|
||||
Message: hook.Commits[len(hook.Commits)-1].Message,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetLogin handles authentication to third party, remote services
|
||||
// and returns the required user data in a standard format.
|
||||
func (b *Bitbucket) GetLogin(w http.ResponseWriter, r *http.Request) (*remote.Login, error) {
|
||||
|
||||
// bitbucket oauth1 consumer
|
||||
consumer := oauth1.Consumer{
|
||||
RequestTokenURL: "https://bitbucket.org/api/1.0/oauth/request_token/",
|
||||
AuthorizationURL: "https://bitbucket.org/!api/1.0/oauth/authenticate",
|
||||
AccessTokenURL: "https://bitbucket.org/api/1.0/oauth/access_token/",
|
||||
CallbackURL: httputil.GetScheme(r) + "://" + httputil.GetHost(r) + "/login/bitbucket.org",
|
||||
ConsumerKey: b.Client,
|
||||
ConsumerSecret: b.Secret,
|
||||
}
|
||||
|
||||
// get the oauth verifier
|
||||
verifier := r.FormValue("oauth_verifier")
|
||||
if len(verifier) == 0 {
|
||||
// Generate a Request Token
|
||||
requestToken, err := consumer.RequestToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add the request token as a signed cookie
|
||||
httputil.SetCookie(w, r, "bitbucket_token", requestToken.Encode())
|
||||
|
||||
url, _ := consumer.AuthorizeRedirect(requestToken)
|
||||
http.Redirect(w, r, url, http.StatusSeeOther)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// remove bitbucket token data once before redirecting
|
||||
// back to the application.
|
||||
defer httputil.DelCookie(w, r, "bitbucket_token")
|
||||
|
||||
// get the tokens from the request
|
||||
requestTokenStr := httputil.GetCookie(r, "bitbucket_token")
|
||||
requestToken, err := oauth1.ParseRequestTokenStr(requestTokenStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// exchange for an access token
|
||||
accessToken, err := consumer.AuthorizeToken(requestToken, verifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create the Bitbucket client
|
||||
client := bitbucket.New(
|
||||
b.Client,
|
||||
b.Secret,
|
||||
accessToken.Token(),
|
||||
accessToken.Secret(),
|
||||
)
|
||||
|
||||
// get the currently authenticated Bitbucket User
|
||||
user, err := client.Users.Current()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// put the user data in the common format
|
||||
login := remote.Login{
|
||||
Login: user.User.Username,
|
||||
Access: accessToken.Token(),
|
||||
Secret: accessToken.Secret(),
|
||||
Name: user.User.DisplayName,
|
||||
}
|
||||
|
||||
return &login, nil
|
||||
}
|
||||
|
||||
// GetClient returns a new Bitbucket remote client.
|
||||
func (b *Bitbucket) GetClient(access, secret string) remote.Client {
|
||||
return &Client{b, access, secret}
|
||||
}
|
||||
|
||||
// IsMatch returns true if the hostname matches the
|
||||
// hostname of this remote client.
|
||||
func (b *Bitbucket) IsMatch(hostname string) bool {
|
||||
return hostname == "bitbucket.org"
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
package bitbucket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/drone/drone/shared/remote"
|
||||
"github.com/drone/go-bitbucket/bitbucket"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
config *Bitbucket
|
||||
access string // user access token
|
||||
secret string // user access token secret
|
||||
}
|
||||
|
||||
// GetUser fetches the user by ID (login name).
|
||||
func (c *Client) GetUser(login string) (*remote.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetRepos fetches all repositories that the specified
|
||||
// user has access to in the remote system.
|
||||
func (c *Client) GetRepos(owner string) ([]*remote.Repo, error) {
|
||||
// create the Bitbucket client
|
||||
client := bitbucket.New(
|
||||
c.config.Client,
|
||||
c.config.Secret,
|
||||
c.access,
|
||||
c.secret,
|
||||
)
|
||||
|
||||
// parse the hostname from the bitbucket url
|
||||
bitbucketurl, err := url.Parse(c.config.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos, err := client.Repos.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// store results in common format
|
||||
result := []*remote.Repo{}
|
||||
|
||||
// loop throught the list and convert to the standard repo format
|
||||
for _, repo := range repos {
|
||||
// for now we only support git repos
|
||||
if repo.Scm != "git" {
|
||||
continue
|
||||
}
|
||||
|
||||
// these are the urls required to clone the repository
|
||||
// TODO use the bitbucketurl.Host and bitbucketurl.Scheme instead of hardcoding
|
||||
// so that we can support Stash.
|
||||
clone := fmt.Sprintf("https://bitbucket.org/%s/%s.git", repo.Owner, repo.Name)
|
||||
ssh := fmt.Sprintf("git@bitbucket.org:%s/%s.git", repo.Owner, repo.Name)
|
||||
|
||||
result = append(result, &remote.Repo{
|
||||
Host: bitbucketurl.Host,
|
||||
Owner: repo.Owner,
|
||||
Name: repo.Name,
|
||||
Kind: repo.Scm,
|
||||
Private: repo.Private,
|
||||
Clone: clone,
|
||||
SSH: ssh,
|
||||
// Bitbucket doesn't return permissions with repository
|
||||
// lists, so we're going to grant full access.
|
||||
//
|
||||
// TODO we need to verify this API call only returns
|
||||
// repositories that we can access (ie not repos we just follow).
|
||||
// otherwise this would cause a security flaw.
|
||||
Push: true,
|
||||
Pull: true,
|
||||
Admin: true,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetScript fetches the build script (.drone.yml) from the remote
|
||||
// repository and returns in string format.
|
||||
func (c *Client) GetScript(hook *remote.Hook) (out string, err error) {
|
||||
// create the Bitbucket client
|
||||
client := bitbucket.New(
|
||||
c.config.Client,
|
||||
c.config.Secret,
|
||||
c.access,
|
||||
c.secret,
|
||||
)
|
||||
|
||||
// get the yaml from the database
|
||||
raw, err := client.Sources.Find(hook.Owner, hook.Repo, hook.Sha, ".drone.yml")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return raw.Data, nil
|
||||
}
|
||||
|
||||
// SetStatus
|
||||
func (c *Client) SetStatus(owner, name, sha, status string) error {
|
||||
// not implemented for Bitbucket
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetActive
|
||||
func (c *Client) SetActive(owner, name, hook, key string) error {
|
||||
// create the Bitbucket client
|
||||
client := bitbucket.New(
|
||||
c.config.Client,
|
||||
c.config.Secret,
|
||||
c.access,
|
||||
c.secret,
|
||||
)
|
||||
|
||||
// parse the hostname from the hook, and use this
|
||||
// to name the ssh key
|
||||
hookurl, err := url.Parse(hook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fetch the repository so that we can see if it
|
||||
// is public or private.
|
||||
repo, err := client.Repos.Find(owner, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if the repository is private we'll need
|
||||
// to upload a github key to the repository
|
||||
if repo.Private {
|
||||
// name the key
|
||||
keyname := "drone@" + hookurl.Host
|
||||
_, err := client.RepoKeys.CreateUpdate(owner, name, key, keyname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// add the hook
|
||||
_, err = client.Brokers.CreateUpdate(owner, name, hook, bitbucket.BrokerTypePost)
|
||||
return err
|
||||
}
|
@@ -1,156 +0,0 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/drone/drone/shared/remote"
|
||||
"github.com/drone/go-github/github"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
config *Github
|
||||
access string // user access token
|
||||
}
|
||||
|
||||
// GetUser fetches the user by ID (login name).
|
||||
func (c *Client) GetUser(login string) (*remote.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetRepos fetches all repositories that the specified
|
||||
// user has access to in the remote system.
|
||||
func (c *Client) GetRepos(owner string) ([]*remote.Repo, error) {
|
||||
// create the github client
|
||||
client := github.New(c.access)
|
||||
|
||||
// retrieve a list of all github repositories
|
||||
repos, err := client.Repos.ListAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// store results in common format
|
||||
result := []*remote.Repo{}
|
||||
|
||||
// parse the hostname from the github url
|
||||
githuburl, err := url.Parse(c.config.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// loop throught the list and convert to the standard repo format
|
||||
for _, repo := range repos {
|
||||
result = append(result, &remote.Repo{
|
||||
ID: repo.ID,
|
||||
Host: githuburl.Host,
|
||||
Owner: repo.Owner.Login,
|
||||
Name: repo.Name,
|
||||
Kind: "git",
|
||||
Clone: repo.CloneUrl,
|
||||
Git: repo.GitUrl,
|
||||
SSH: repo.SshUrl,
|
||||
Private: repo.Private,
|
||||
Push: repo.Permissions.Push,
|
||||
Pull: repo.Permissions.Pull,
|
||||
Admin: repo.Permissions.Admin,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetScript fetches the build script (.drone.yml) from the remote
|
||||
// repository using the GitHub API and returns the raw file in string format.
|
||||
func (c *Client) GetScript(hook *remote.Hook) (out string, err error) {
|
||||
// create the github client
|
||||
client := github.New(c.access)
|
||||
|
||||
// retrieve the .drone.yml file from GitHub
|
||||
content, err := client.Contents.FindRef(hook.Owner, hook.Repo, ".drone.yml", hook.Sha)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// decode the content
|
||||
raw, err := content.DecodeContent()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return string(raw), nil
|
||||
}
|
||||
|
||||
// SetStatus
|
||||
func (c *Client) SetStatus(owner, name, sha, status string) error {
|
||||
// create the github client
|
||||
client := github.New(c.access)
|
||||
|
||||
// convert from drone status to github status
|
||||
var message string
|
||||
switch status {
|
||||
case "Success":
|
||||
status = "success"
|
||||
message = "The build succeeded on drone.io"
|
||||
case "Failure":
|
||||
status = "failure"
|
||||
message = "The build failed on drone.io"
|
||||
case "Started", "Pending":
|
||||
status = "pending"
|
||||
message = "The build is pending on drone.io"
|
||||
default:
|
||||
status = "error"
|
||||
message = "The build errored on drone.io"
|
||||
}
|
||||
|
||||
// format the build URL
|
||||
// TODO we really need the branch here
|
||||
// TODO we really need the drone.io hostname as well
|
||||
url := fmt.Sprintf("http://beta.drone.io/%s/%s/%s/%s", owner, name, "master", sha)
|
||||
|
||||
// update the status
|
||||
return client.Repos.CreateStatus(owner, name, status, url, message, sha)
|
||||
}
|
||||
|
||||
// SetActive will configure a post-commit and pull-request hook
|
||||
// with the remote GitHub repository using the GitHub API.
|
||||
//
|
||||
// It will also, optionally, add a public RSA key. This is primarily
|
||||
// used for private repositories, which typically must use the Git+SSH
|
||||
// protocol to clone the repository.
|
||||
func (c *Client) SetActive(owner, name, hook, key string) error {
|
||||
// create the github client
|
||||
client := github.New(c.access)
|
||||
|
||||
// parse the hostname from the hook, and use this
|
||||
// to name the ssh key
|
||||
hookurl, err := url.Parse(hook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fetch the repository so that we can see if it
|
||||
// is public or private.
|
||||
repo, err := client.Repos.Find(owner, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if the repository is private we'll need
|
||||
// to upload a github key to the repository
|
||||
if repo.Private {
|
||||
// name the key
|
||||
keyname := "drone@" + hookurl.Host
|
||||
_, err := client.RepoKeys.CreateUpdate(owner, name, key, keyname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// add the hook
|
||||
if _, err := client.Hooks.CreateUpdate(owner, name, hook); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,201 +0,0 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/shared/remote"
|
||||
"github.com/drone/drone/shared/util/httputil"
|
||||
"github.com/drone/go-github/github"
|
||||
"github.com/drone/go-github/oauth2"
|
||||
)
|
||||
|
||||
var (
|
||||
scope = "repo,repo:status,user:email"
|
||||
state = "FqB4EbagQ2o"
|
||||
)
|
||||
|
||||
type Github struct {
|
||||
URL string `json:"url"` // https://github.com
|
||||
API string `json:"api"` // https://api.github.com
|
||||
Client string `json:"client"`
|
||||
Secret string `json:"secret"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// GetName returns the name of this remote system.
|
||||
func (g *Github) GetName() string {
|
||||
switch g.URL {
|
||||
case "https://github.com":
|
||||
return "github.com"
|
||||
default:
|
||||
return "enterprise.github.com"
|
||||
}
|
||||
}
|
||||
|
||||
// GetHost returns the url.Host of this remote system.
|
||||
func (g *Github) GetHost() (host string) {
|
||||
u, err := url.Parse(g.URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return u.Host
|
||||
}
|
||||
|
||||
// GetHook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func (g *Github) GetHook(r *http.Request) (*remote.Hook, error) {
|
||||
// handle github ping
|
||||
if r.Header.Get("X-Github-Event") == "ping" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// handle github pull request hook differently
|
||||
if r.Header.Get("X-Github-Event") == "pull_request" {
|
||||
return g.GetPullRequestHook(r)
|
||||
}
|
||||
|
||||
// get the payload of the message
|
||||
payload := r.FormValue("payload")
|
||||
|
||||
// parse the github Hook payload
|
||||
data, err := github.ParseHook([]byte(payload))
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// make sure this is being triggered because of a commit
|
||||
// and not something like a tag deletion or whatever
|
||||
if data.IsTag() || data.IsGithubPages() ||
|
||||
data.IsHead() == false || data.IsDeleted() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hook := remote.Hook{}
|
||||
hook.Repo = data.Repo.Name
|
||||
hook.Owner = data.Repo.Owner.Login
|
||||
hook.Sha = data.Head.Id
|
||||
hook.Branch = data.Branch()
|
||||
|
||||
if len(hook.Owner) == 0 {
|
||||
hook.Owner = data.Repo.Owner.Name
|
||||
}
|
||||
|
||||
// extract the author and message from the commit
|
||||
// this is kind of experimental, since I don't know
|
||||
// what I'm doing here.
|
||||
if data.Head != nil && data.Head.Author != nil {
|
||||
hook.Message = data.Head.Message
|
||||
hook.Timestamp = data.Head.Timestamp
|
||||
hook.Author = data.Head.Author.Email
|
||||
} else if data.Commits != nil && len(data.Commits) > 0 && data.Commits[0].Author != nil {
|
||||
hook.Message = data.Commits[0].Message
|
||||
hook.Timestamp = data.Commits[0].Timestamp
|
||||
hook.Author = data.Commits[0].Author.Email
|
||||
}
|
||||
|
||||
return &hook, nil
|
||||
}
|
||||
|
||||
func (g *Github) GetPullRequestHook(r *http.Request) (*remote.Hook, error) {
|
||||
payload := r.FormValue("payload")
|
||||
|
||||
// parse the payload to retrieve the pull-request
|
||||
// hook meta-data.
|
||||
data, err := github.ParsePullRequestHook([]byte(payload))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ignore these
|
||||
if data.Action != "opened" && data.Action != "synchronize" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO we should also store the pull request branch (ie from x to y)
|
||||
// we can find it here: data.PullRequest.Head.Ref
|
||||
hook := remote.Hook{
|
||||
Owner: data.Repo.Owner.Login,
|
||||
Repo: data.Repo.Name,
|
||||
Sha: data.PullRequest.Head.Sha,
|
||||
Branch: data.PullRequest.Base.Ref,
|
||||
Author: data.PullRequest.User.Login,
|
||||
Gravatar: data.PullRequest.User.GravatarId,
|
||||
Timestamp: time.Now().UTC().String(),
|
||||
Message: data.PullRequest.Title,
|
||||
PullRequest: strconv.Itoa(data.Number),
|
||||
}
|
||||
|
||||
if len(hook.Owner) == 0 {
|
||||
hook.Owner = data.Repo.Owner.Name
|
||||
}
|
||||
|
||||
return &hook, nil
|
||||
}
|
||||
|
||||
// GetLogin handles authentication to third party, remote services
|
||||
// and returns the required user data in a standard format.
|
||||
func (g *Github) GetLogin(w http.ResponseWriter, r *http.Request) (*remote.Login, error) {
|
||||
// create the oauth2 client
|
||||
oauth := oauth2.Client{
|
||||
RedirectURL: fmt.Sprintf("%s://%s/login/github.com", httputil.GetScheme(r), httputil.GetHost(r)),
|
||||
AccessTokenURL: fmt.Sprintf("%s/login/oauth/access_token", g.URL),
|
||||
AuthorizationURL: fmt.Sprintf("%s/login/oauth/authorize", g.URL),
|
||||
ClientId: g.Client,
|
||||
ClientSecret: g.Secret,
|
||||
}
|
||||
|
||||
// get the OAuth code
|
||||
code := r.FormValue("code")
|
||||
if len(code) == 0 {
|
||||
redirect := oauth.AuthorizeRedirect(scope, state)
|
||||
http.Redirect(w, r, redirect, http.StatusSeeOther)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// exchange code for an auth token
|
||||
token, err := oauth.GrantToken(code)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error granting GitHub authorization token. %s", err)
|
||||
}
|
||||
|
||||
// create the client
|
||||
client := github.New(token.AccessToken)
|
||||
|
||||
// get the user information
|
||||
user, err := client.Users.Current()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error retrieving currently authenticated GitHub user. %s", err)
|
||||
}
|
||||
|
||||
// put the user data in the common format
|
||||
login := remote.Login{
|
||||
ID: user.ID,
|
||||
Login: user.Login,
|
||||
Access: token.AccessToken,
|
||||
Name: user.Name,
|
||||
}
|
||||
|
||||
// get the users primary email address
|
||||
email, err := client.Emails.FindPrimary()
|
||||
if err == nil {
|
||||
login.Email = email.Email
|
||||
}
|
||||
|
||||
return &login, nil
|
||||
}
|
||||
|
||||
// GetClient returns a new Github remote client.
|
||||
func (g *Github) GetClient(access, secret string) remote.Client {
|
||||
return &Client{g, access}
|
||||
}
|
||||
|
||||
// IsMatch returns true if the hostname matches the
|
||||
// hostname of this remote client.
|
||||
func (g *Github) IsMatch(hostname string) bool {
|
||||
return strings.HasSuffix(hostname, g.URL)
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/remote"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
config *Gitlab
|
||||
access string // user access token
|
||||
}
|
||||
|
||||
// GetUser fetches the user by ID (login name).
|
||||
func (c *Client) GetUser(login string) (*remote.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetRepos fetches all repositories that the specified
|
||||
// user has access to in the remote system.
|
||||
func (c *Client) GetRepos(owner string) ([]*remote.Repo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetScript fetches the build script (.drone.yml) from the remote
|
||||
// repository and returns in string format.
|
||||
func (c *Client) GetScript(*remote.Hook) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// SetStatus
|
||||
func (c *Client) SetStatus(owner, repo, sha, status string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetActive
|
||||
func (c *Client) SetActive(owner, repo, hook, key string) error {
|
||||
return nil
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
package gitlab
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/shared/remote"
|
||||
)
|
||||
|
||||
type Gitlab struct {
|
||||
URL string `json:"url"` // https://github.com
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// GetName returns the name of this remote system.
|
||||
func (g *Gitlab) GetName() string {
|
||||
return "gitlab.com"
|
||||
}
|
||||
|
||||
// GetHost returns the url.Host of this remote system.
|
||||
func (g *Gitlab) GetHost() (host string) {
|
||||
u, err := url.Parse(g.URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return u.Host
|
||||
}
|
||||
|
||||
// GetHook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func (g *Gitlab) GetHook(*http.Request) (*remote.Hook, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetLogin handles authentication to third party, remote services
|
||||
// and returns the required user data in a standard format.
|
||||
func (g *Gitlab) GetLogin(http.ResponseWriter, *http.Request) (*remote.Login, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetClient returns a new Gitlab remote client.
|
||||
func (g *Gitlab) GetClient(access, secret string) remote.Client {
|
||||
return &Client{g, access}
|
||||
}
|
||||
|
||||
// IsMatch returns true if the hostname matches the
|
||||
// hostname of this remote client.
|
||||
func (g *Gitlab) IsMatch(hostname string) bool {
|
||||
return strings.HasSuffix(hostname, g.URL)
|
||||
}
|
@@ -1,99 +0,0 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Remote interface {
|
||||
// GetName returns the name of this remote system.
|
||||
GetName() string
|
||||
|
||||
// GetHost returns the URL hostname of this remote system.
|
||||
GetHost() (host string)
|
||||
|
||||
// GetHook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
GetHook(*http.Request) (*Hook, error)
|
||||
|
||||
// GetLogin handles authentication to third party, remote services
|
||||
// and returns the required user data in a standard format.
|
||||
GetLogin(http.ResponseWriter, *http.Request) (*Login, error)
|
||||
|
||||
// NewClient returns a new Bitbucket remote client.
|
||||
GetClient(access, secret string) Client
|
||||
|
||||
// Match returns true if the hostname matches the
|
||||
// hostname of this remote client.
|
||||
IsMatch(hostname string) bool
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
// GetUser fetches the user by ID (login name).
|
||||
GetUser(login string) (*User, error)
|
||||
|
||||
// GetRepos fetches all repositories that the specified
|
||||
// user has access to in the remote system.
|
||||
GetRepos(owner string) ([]*Repo, error)
|
||||
|
||||
// GetScript fetches the build script (.drone.yml) from the remote
|
||||
// repository and returns in string format.
|
||||
GetScript(*Hook) (string, error)
|
||||
|
||||
// SetStatus
|
||||
SetStatus(owner, repo, sha, status string) error
|
||||
|
||||
// SetActive
|
||||
SetActive(owner, repo, hook, key string) error
|
||||
}
|
||||
|
||||
// Hook represents a subset of commit meta-data provided
|
||||
// by post-commit and pull request hooks.
|
||||
type Hook struct {
|
||||
Owner string
|
||||
Repo string
|
||||
Sha string
|
||||
Branch string
|
||||
PullRequest string
|
||||
Author string
|
||||
Gravatar string
|
||||
Timestamp string
|
||||
Message string
|
||||
}
|
||||
|
||||
// Login represents a standard subset of user meta-data
|
||||
// provided by OAuth login services.
|
||||
type Login struct {
|
||||
ID int64
|
||||
Login string
|
||||
Access string
|
||||
Secret string
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
// User represents a standard subset of user meta-data
|
||||
// returned by REST API user endpoints (ie github user api).
|
||||
type User struct {
|
||||
ID int64
|
||||
Login string
|
||||
Name string
|
||||
Gravatar string
|
||||
}
|
||||
|
||||
// Repo represents a standard subset of repository meta-data
|
||||
// returned by REST API endpoints (ie github repo api).
|
||||
type Repo struct {
|
||||
ID int64
|
||||
Host string
|
||||
Owner string
|
||||
Name string
|
||||
Kind string
|
||||
Clone string
|
||||
Git string
|
||||
SSH string
|
||||
URL string
|
||||
Private bool
|
||||
Pull bool
|
||||
Push bool
|
||||
Admin bool
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package stash
|
||||
|
||||
import (
|
||||
"github.com/drone/drone/shared/remote"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
config *Stash
|
||||
access string // user access token
|
||||
secret string // user access token secret
|
||||
}
|
||||
|
||||
// GetUser fetches the user by ID (login name).
|
||||
func (c *Client) GetUser(login string) (*remote.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetRepos fetches all repositories that the specified
|
||||
// user has access to in the remote system.
|
||||
func (c *Client) GetRepos(owner string) ([]*remote.Repo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetScript fetches the build script (.drone.yml) from the remote
|
||||
// repository and returns in string format.
|
||||
func (c *Client) GetScript(*remote.Hook) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// SetStatus
|
||||
func (c *Client) SetStatus(owner, repo, sha, status string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetActive
|
||||
func (c *Client) SetActive(owner, repo, hook, key string) error {
|
||||
return nil
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
package stash
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/shared/remote"
|
||||
)
|
||||
|
||||
type Stash struct {
|
||||
URL string `json:"url"` // https://bitbucket.org
|
||||
API string `json:"api"` // https://api.bitbucket.org
|
||||
Client string `json:"client"`
|
||||
Secret string `json:"secret"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// GetName returns the name of this remote system.
|
||||
func (s *Stash) GetName() string {
|
||||
return "stash.atlassian.com"
|
||||
}
|
||||
|
||||
// GetHost returns the url.Host of this remote system.
|
||||
func (s *Stash) GetHost() (host string) {
|
||||
u, err := url.Parse(s.URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return u.Host
|
||||
}
|
||||
|
||||
// GetHook parses the post-commit hook from the Request body
|
||||
// and returns the required data in a standard format.
|
||||
func (s *Stash) GetHook(*http.Request) (*remote.Hook, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetLogin handles authentication to third party, remote services
|
||||
// and returns the required user data in a standard format.
|
||||
func (s *Stash) GetLogin(http.ResponseWriter, *http.Request) (*remote.Login, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetClient returns a new Stash remote client.
|
||||
func (s *Stash) GetClient(access, secret string) remote.Client {
|
||||
return &Client{s, access, secret}
|
||||
}
|
||||
|
||||
// IsMatch returns true if the hostname matches the
|
||||
// hostname of this remote client.
|
||||
func (s *Stash) IsMatch(hostname string) bool {
|
||||
return strings.HasSuffix(hostname, s.URL)
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
cobertura.go
|
||||
coveralls.go
|
||||
gocov.go
|
||||
junit.go
|
||||
phpunit.go
|
@@ -1,9 +0,0 @@
|
||||
package smtp
|
||||
|
||||
type SMTP struct {
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
From string `json:"from"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
Reference in New Issue
Block a user