Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
485ddb39a5
41 changed files with 828 additions and 120 deletions
|
@ -114,6 +114,7 @@ secret=""
|
||||||
|
|
||||||
[gitlab]
|
[gitlab]
|
||||||
url=""
|
url=""
|
||||||
|
skip_verify=false
|
||||||
|
|
||||||
[smtp]
|
[smtp]
|
||||||
host=""
|
host=""
|
||||||
|
@ -122,9 +123,11 @@ from=""
|
||||||
user=""
|
user=""
|
||||||
pass=""
|
pass=""
|
||||||
|
|
||||||
[worker]
|
[docker]
|
||||||
cert=""
|
cert=""
|
||||||
key=""
|
key=""
|
||||||
|
|
||||||
|
[worker]
|
||||||
nodes=[
|
nodes=[
|
||||||
"unix:///var/run/docker.sock",
|
"unix:///var/run/docker.sock",
|
||||||
"unix:///var/run/docker.sock"
|
"unix:///var/run/docker.sock"
|
||||||
|
@ -169,6 +172,7 @@ export DRONE_BITBUCKET_SECRET=""
|
||||||
|
|
||||||
# gitlab configuration
|
# gitlab configuration
|
||||||
export DRONE_GITLAB_URL=""
|
export DRONE_GITLAB_URL=""
|
||||||
|
export DRONE_GITLAB_SKIP_VERIFY=false
|
||||||
|
|
||||||
# email configuration
|
# email configuration
|
||||||
export DRONE_SMTP_HOST=""
|
export DRONE_SMTP_HOST=""
|
||||||
|
@ -216,4 +220,4 @@ You will need to include a `.drone.yml` file in the root of your repository in o
|
||||||
configure a build. I'm still working on updated documentation, so in the meantime please refer
|
configure a build. I'm still working on updated documentation, so in the meantime please refer
|
||||||
to the `0.2` README to learn more about the `.drone.yml` format:
|
to the `0.2` README to learn more about the `.drone.yml` format:
|
||||||
|
|
||||||
https://github.com/drone/drone/blob/v0.2.1/README.md#builds
|
https://github.com/drone/drone/blob/v0.2.1/README.md#builds
|
||||||
|
|
32
cli/build.go
32
cli/build.go
|
@ -43,17 +43,17 @@ func NewBuildCommand() cli.Command {
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "docker-host",
|
Name: "docker-host",
|
||||||
Value: "",
|
Value: getHost(),
|
||||||
Usage: "docker daemon address",
|
Usage: "docker daemon address",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "docker-cert",
|
Name: "docker-cert",
|
||||||
Value: "",
|
Value: getCert(),
|
||||||
Usage: "docker daemon tls certificate",
|
Usage: "docker daemon tls certificate",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "docker-key",
|
Name: "docker-key",
|
||||||
Value: "",
|
Value: getKey(),
|
||||||
Usage: "docker daemon tls key",
|
Usage: "docker daemon tls key",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -115,7 +115,7 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl
|
||||||
envs := getParamMap("DRONE_ENV_")
|
envs := getParamMap("DRONE_ENV_")
|
||||||
|
|
||||||
// parse the Drone yml file
|
// parse the Drone yml file
|
||||||
s, err := script.ParseBuildFile(script.Inject(path, envs))
|
s, err := script.ParseBuildFile(path, envs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err.Error())
|
log.Err(err.Error())
|
||||||
return EXIT_STATUS, err
|
return EXIT_STATUS, err
|
||||||
|
@ -127,10 +127,10 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl
|
||||||
}
|
}
|
||||||
|
|
||||||
if deploy == false {
|
if deploy == false {
|
||||||
s.Publish = nil
|
s.Deploy = nil
|
||||||
}
|
}
|
||||||
if publish == false {
|
if publish == false {
|
||||||
s.Deploy = nil
|
s.Publish = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the repository root directory
|
// get the repository root directory
|
||||||
|
@ -204,3 +204,23 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl
|
||||||
|
|
||||||
return builder.BuildState.ExitCode, nil
|
return builder.BuildState.ExitCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getHost() string {
|
||||||
|
return os.Getenv("DOCKER_HOST")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCert() string {
|
||||||
|
if os.Getenv("DOCKER_CERT_PATH") != "" && os.Getenv("DOCKER_TLS_VERIFY") == "1" {
|
||||||
|
return filepath.Join(os.Getenv("DOCKER_CERT_PATH"), "cert.pem")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKey() string {
|
||||||
|
if os.Getenv("DOCKER_CERT_PATH") != "" && os.Getenv("DOCKER_TLS_VERIFY") == "1" {
|
||||||
|
return filepath.Join(os.Getenv("DOCKER_CERT_PATH"), "key.pem")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ port=":80"
|
||||||
|
|
||||||
# [session]
|
# [session]
|
||||||
# secret=""
|
# secret=""
|
||||||
# duration=""
|
# expires=""
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
# Database configuration, by default using SQLite3.
|
# Database configuration, by default using SQLite3.
|
||||||
|
@ -51,6 +51,7 @@ datasource="/var/lib/drone/drone.sqlite"
|
||||||
|
|
||||||
# [gitlab]
|
# [gitlab]
|
||||||
# url=""
|
# url=""
|
||||||
|
# skip_verify=false
|
||||||
|
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
@ -64,10 +65,12 @@ datasource="/var/lib/drone/drone.sqlite"
|
||||||
# user=""
|
# user=""
|
||||||
# pass=""
|
# pass=""
|
||||||
|
|
||||||
# [worker]
|
# [docker]
|
||||||
# cert=""
|
# cert=""
|
||||||
# key=""
|
# key=""
|
||||||
|
|
||||||
|
# [worker]
|
||||||
# nodes=[
|
# nodes=[
|
||||||
# "unix:///var/run/docker.sock",
|
# "unix:///var/run/docker.sock",
|
||||||
# "unix:///var/run/docker.sock"
|
# "unix:///var/run/docker.sock"
|
||||||
# ]
|
# ]
|
||||||
|
|
56
plugin/deploy/deis/deis.go
Normal file
56
plugin/deploy/deis/deis.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package deis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/drone/drone/plugin/condition"
|
||||||
|
"github.com/drone/drone/shared/build/buildfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Gommand to the current commit hash
|
||||||
|
CmdRevParse = "COMMIT=$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
// Command to set the git user and email based on the
|
||||||
|
// individual that made the commit.
|
||||||
|
CmdGlobalEmail = "git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')"
|
||||||
|
CmdGlobalUser = "git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')"
|
||||||
|
)
|
||||||
|
|
||||||
|
// deploy:
|
||||||
|
// deis:
|
||||||
|
// app: safe-island-6261
|
||||||
|
// deisurl: deis.myurl.tdl:2222/
|
||||||
|
|
||||||
|
type Deis struct {
|
||||||
|
App string `yaml:"app,omitempty"`
|
||||||
|
Force bool `yaml:"force,omitempty"`
|
||||||
|
Deisurl string `yaml:"deisurl,omitempty"`
|
||||||
|
Condition *condition.Condition `yaml:"when,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Deis) Write(f *buildfile.Buildfile) {
|
||||||
|
f.WriteCmdSilent(CmdRevParse)
|
||||||
|
f.WriteCmdSilent(CmdGlobalUser)
|
||||||
|
f.WriteCmdSilent(CmdGlobalEmail)
|
||||||
|
|
||||||
|
// git@deis.yourdomain.com:2222/drone.git
|
||||||
|
|
||||||
|
f.WriteCmd(fmt.Sprintf("git remote add deis ssh://git@%s%s.git", h.Deisurl , 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 Deis.
|
||||||
|
f.WriteCmd(fmt.Sprintf("git add -A"))
|
||||||
|
f.WriteCmd(fmt.Sprintf("git commit -m 'adding build artifacts'"))
|
||||||
|
f.WriteCmd(fmt.Sprintf("git push deis HEAD:master --force"))
|
||||||
|
case false:
|
||||||
|
// otherwise we just do a standard git push
|
||||||
|
f.WriteCmd(fmt.Sprintf("git push deis $COMMIT:master"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Deis) GetCondition() *condition.Condition {
|
||||||
|
return h.Condition
|
||||||
|
}
|
68
plugin/deploy/deis/deis_test.go
Normal file
68
plugin/deploy/deis/deis_test.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package deis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/drone/drone/shared/build/buildfile"
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Deis(t *testing.T) {
|
||||||
|
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
g.Describe("Deis Deploy", func() {
|
||||||
|
|
||||||
|
g.It("Should set git.config", func() {
|
||||||
|
b := new(buildfile.Buildfile)
|
||||||
|
h := Deis{
|
||||||
|
App: "drone",
|
||||||
|
Deisurl: "deis.yourdomain.com:2222",
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write(b)
|
||||||
|
out := b.String()
|
||||||
|
g.Assert(strings.Contains(out, CmdRevParse)).Equal(true)
|
||||||
|
g.Assert(strings.Contains(out, CmdGlobalUser)).Equal(true)
|
||||||
|
g.Assert(strings.Contains(out, CmdGlobalEmail)).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should add remote", func() {
|
||||||
|
b := new(buildfile.Buildfile)
|
||||||
|
h := Deis{
|
||||||
|
App: "drone",
|
||||||
|
Deisurl: "deis.yourdomain.com:2222/",
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write(b)
|
||||||
|
out := b.String()
|
||||||
|
g.Assert(strings.Contains(out, "\ngit remote add deis ssh://git@deis.yourdomain.com:2222/drone.git\n")).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should push to remote", func() {
|
||||||
|
b := new(buildfile.Buildfile)
|
||||||
|
d := Deis{
|
||||||
|
App: "drone",
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Write(b)
|
||||||
|
out := b.String()
|
||||||
|
g.Assert(strings.Contains(out, "\ngit push deis $COMMIT:master\n")).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should force push to remote", func() {
|
||||||
|
b := new(buildfile.Buildfile)
|
||||||
|
h := Deis{
|
||||||
|
Force: true,
|
||||||
|
App: "drone",
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write(b)
|
||||||
|
out := b.String()
|
||||||
|
g.Assert(strings.Contains(out, "\ngit add -A\n")).Equal(true)
|
||||||
|
g.Assert(strings.Contains(out, "\ngit commit -m 'adding build artifacts'\n")).Equal(true)
|
||||||
|
g.Assert(strings.Contains(out, "\ngit push deis HEAD:master --force\n")).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/drone/drone/plugin/deploy/git"
|
"github.com/drone/drone/plugin/deploy/git"
|
||||||
"github.com/drone/drone/plugin/deploy/heroku"
|
"github.com/drone/drone/plugin/deploy/heroku"
|
||||||
|
"github.com/drone/drone/plugin/deploy/deis"
|
||||||
"github.com/drone/drone/plugin/deploy/modulus"
|
"github.com/drone/drone/plugin/deploy/modulus"
|
||||||
"github.com/drone/drone/plugin/deploy/nodejitsu"
|
"github.com/drone/drone/plugin/deploy/nodejitsu"
|
||||||
"github.com/drone/drone/plugin/deploy/tsuru"
|
"github.com/drone/drone/plugin/deploy/tsuru"
|
||||||
|
@ -19,6 +20,7 @@ type Deploy struct {
|
||||||
CloudFoundry *CloudFoundry `yaml:"cloudfoundry,omitempty"`
|
CloudFoundry *CloudFoundry `yaml:"cloudfoundry,omitempty"`
|
||||||
Git *git.Git `yaml:"git,omitempty"`
|
Git *git.Git `yaml:"git,omitempty"`
|
||||||
Heroku *heroku.Heroku `yaml:"heroku,omitempty"`
|
Heroku *heroku.Heroku `yaml:"heroku,omitempty"`
|
||||||
|
Deis *deis.Deis `yaml:"deis,omitempty"`
|
||||||
Modulus *modulus.Modulus `yaml:"modulus,omitempty"`
|
Modulus *modulus.Modulus `yaml:"modulus,omitempty"`
|
||||||
Nodejitsu *nodejitsu.Nodejitsu `yaml:"nodejitsu,omitempty"`
|
Nodejitsu *nodejitsu.Nodejitsu `yaml:"nodejitsu,omitempty"`
|
||||||
SSH *SSH `yaml:"ssh,omitempty"`
|
SSH *SSH `yaml:"ssh,omitempty"`
|
||||||
|
@ -37,6 +39,9 @@ func (d *Deploy) Write(f *buildfile.Buildfile, r *repo.Repo) {
|
||||||
if d.Heroku != nil && match(d.Heroku.GetCondition(), r) {
|
if d.Heroku != nil && match(d.Heroku.GetCondition(), r) {
|
||||||
d.Heroku.Write(f)
|
d.Heroku.Write(f)
|
||||||
}
|
}
|
||||||
|
if d.Deis != nil && match(d.Deis.GetCondition(), r) {
|
||||||
|
d.Deis.Write(f)
|
||||||
|
}
|
||||||
if d.Modulus != nil && match(d.Modulus.GetCondition(), r) {
|
if d.Modulus != nil && match(d.Modulus.GetCondition(), r) {
|
||||||
d.Modulus.Write(f)
|
d.Modulus.Write(f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,16 @@ const (
|
||||||
// individual that made the commit.
|
// individual that made the commit.
|
||||||
CmdGlobalEmail = "git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')"
|
CmdGlobalEmail = "git config --global user.email $(git --no-pager log -1 --pretty=format:'%ae')"
|
||||||
CmdGlobalUser = "git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')"
|
CmdGlobalUser = "git config --global user.name $(git --no-pager log -1 --pretty=format:'%an')"
|
||||||
|
|
||||||
|
// Command to write the API token to ~/.netrc
|
||||||
|
// use "_" since heroku git authentication ignores username
|
||||||
|
CmdLogin = "echo 'machine git.heroku.com login _ password %s' >> ~/.netrc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Heroku struct {
|
type Heroku struct {
|
||||||
App string `yaml:"app,omitempty"`
|
App string `yaml:"app,omitempty"`
|
||||||
Force bool `yaml:"force,omitempty"`
|
Force bool `yaml:"force,omitempty"`
|
||||||
|
Token string `yaml:"token,omitempty"`
|
||||||
|
|
||||||
Condition *condition.Condition `yaml:"when,omitempty"`
|
Condition *condition.Condition `yaml:"when,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -27,9 +32,10 @@ func (h *Heroku) Write(f *buildfile.Buildfile) {
|
||||||
f.WriteCmdSilent(CmdRevParse)
|
f.WriteCmdSilent(CmdRevParse)
|
||||||
f.WriteCmdSilent(CmdGlobalUser)
|
f.WriteCmdSilent(CmdGlobalUser)
|
||||||
f.WriteCmdSilent(CmdGlobalEmail)
|
f.WriteCmdSilent(CmdGlobalEmail)
|
||||||
|
f.WriteCmdSilent(fmt.Sprintf(CmdLogin, h.Token))
|
||||||
|
|
||||||
// add heroku as a git remote
|
// add heroku as a git remote
|
||||||
f.WriteCmd(fmt.Sprintf("git remote add heroku git@heroku.com:%s.git", h.App))
|
f.WriteCmd(fmt.Sprintf("git remote add heroku https://git.heroku.com/%s.git", h.App))
|
||||||
|
|
||||||
switch h.Force {
|
switch h.Force {
|
||||||
case true:
|
case true:
|
||||||
|
@ -38,10 +44,10 @@ func (h *Heroku) Write(f *buildfile.Buildfile) {
|
||||||
// that need to be deployed to Heroku.
|
// that need to be deployed to Heroku.
|
||||||
f.WriteCmd(fmt.Sprintf("git add -A"))
|
f.WriteCmd(fmt.Sprintf("git add -A"))
|
||||||
f.WriteCmd(fmt.Sprintf("git commit -m 'adding build artifacts'"))
|
f.WriteCmd(fmt.Sprintf("git commit -m 'adding build artifacts'"))
|
||||||
f.WriteCmd(fmt.Sprintf("git push heroku HEAD:master --force"))
|
f.WriteCmd(fmt.Sprintf("git push heroku HEAD:refs/heads/master --force"))
|
||||||
case false:
|
case false:
|
||||||
// otherwise we just do a standard git push
|
// otherwise we just do a standard git push
|
||||||
f.WriteCmd(fmt.Sprintf("git push heroku $COMMIT:master"))
|
f.WriteCmd(fmt.Sprintf("git push heroku $COMMIT:refs/heads/master"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,18 @@ func Test_Heroku(t *testing.T) {
|
||||||
g.Assert(strings.Contains(out, CmdGlobalEmail)).Equal(true)
|
g.Assert(strings.Contains(out, CmdGlobalEmail)).Equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
g.It("Should write token", func() {
|
||||||
|
b := new(buildfile.Buildfile)
|
||||||
|
h := Heroku{
|
||||||
|
App: "drone",
|
||||||
|
Token: "mock-token",
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write(b)
|
||||||
|
out := b.String()
|
||||||
|
g.Assert(strings.Contains(out, "\necho 'machine git.heroku.com login _ password mock-token' >> ~/.netrc\n")).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
g.It("Should add remote", func() {
|
g.It("Should add remote", func() {
|
||||||
b := new(buildfile.Buildfile)
|
b := new(buildfile.Buildfile)
|
||||||
h := Heroku{
|
h := Heroku{
|
||||||
|
@ -34,7 +46,7 @@ func Test_Heroku(t *testing.T) {
|
||||||
|
|
||||||
h.Write(b)
|
h.Write(b)
|
||||||
out := b.String()
|
out := b.String()
|
||||||
g.Assert(strings.Contains(out, "\ngit remote add heroku git@heroku.com:drone.git\n")).Equal(true)
|
g.Assert(strings.Contains(out, "\ngit remote add heroku https://git.heroku.com/drone.git\n")).Equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should push to remote", func() {
|
g.It("Should push to remote", func() {
|
||||||
|
@ -45,7 +57,7 @@ func Test_Heroku(t *testing.T) {
|
||||||
|
|
||||||
d.Write(b)
|
d.Write(b)
|
||||||
out := b.String()
|
out := b.String()
|
||||||
g.Assert(strings.Contains(out, "\ngit push heroku $COMMIT:master\n")).Equal(true)
|
g.Assert(strings.Contains(out, "\ngit push heroku $COMMIT:refs/heads/master\n")).Equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should force push to remote", func() {
|
g.It("Should force push to remote", func() {
|
||||||
|
@ -59,7 +71,7 @@ func Test_Heroku(t *testing.T) {
|
||||||
out := b.String()
|
out := b.String()
|
||||||
g.Assert(strings.Contains(out, "\ngit add -A\n")).Equal(true)
|
g.Assert(strings.Contains(out, "\ngit add -A\n")).Equal(true)
|
||||||
g.Assert(strings.Contains(out, "\ngit commit -m 'adding build artifacts'\n")).Equal(true)
|
g.Assert(strings.Contains(out, "\ngit commit -m 'adding build artifacts'\n")).Equal(true)
|
||||||
g.Assert(strings.Contains(out, "\ngit push heroku HEAD:master --force\n")).Equal(true)
|
g.Assert(strings.Contains(out, "\ngit push heroku HEAD:refs/heads/master --force\n")).Equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -53,11 +53,23 @@ func (i *IRC) sendSuccess(req *model.Request) error {
|
||||||
// to the connected IRC client
|
// to the connected IRC client
|
||||||
func (i *IRC) send(channel string, message string) error {
|
func (i *IRC) send(channel string, message string) error {
|
||||||
client := irc.IRC(i.Nick, i.Nick)
|
client := irc.IRC(i.Nick, i.Nick)
|
||||||
if client != nil {
|
|
||||||
|
if client == nil {
|
||||||
return fmt.Errorf("Error creating IRC client")
|
return fmt.Errorf("Error creating IRC client")
|
||||||
}
|
}
|
||||||
defer client.Disconnect()
|
|
||||||
client.Connect(i.Server)
|
err := client.Connect(i.Server)
|
||||||
client.Notice(channel, message)
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error connecting to IRC server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.AddCallback("001", func(_ *irc.Event) {
|
||||||
|
client.Notice(channel, message)
|
||||||
|
client.Quit()
|
||||||
|
})
|
||||||
|
|
||||||
|
go client.Loop()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
139
plugin/notify/katoim/katoim.go
Normal file
139
plugin/notify/katoim/katoim.go
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
package katoim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/drone/drone/shared/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
katoimEndpoint = "https://api.kato.im/rooms/%s/simple"
|
||||||
|
katoimStartedMessage = "*Building* %s, commit [%s](%s), author %s"
|
||||||
|
katoimSuccessMessage = "*Success* %s, commit [%s](%s), author %s"
|
||||||
|
katoimFailureMessage = "*Failed* %s, commit [%s](%s), author %s"
|
||||||
|
|
||||||
|
NotifyTrue = "true"
|
||||||
|
NotifyFalse = "false"
|
||||||
|
NotifyOn = "on"
|
||||||
|
NotifyOff = "off"
|
||||||
|
NotifyNever = "never"
|
||||||
|
NotifyAlways = "always"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KatoIM struct {
|
||||||
|
RoomID string `yaml:"room_id,omitempty"`
|
||||||
|
Started string `yaml:"on_started,omitempty"`
|
||||||
|
Success string `yaml:"on_success,omitempty"`
|
||||||
|
Failure string `yaml:"on_failure,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KatoIM) Send(context *model.Request) error {
|
||||||
|
switch {
|
||||||
|
case context.Commit.Status == model.StatusStarted:
|
||||||
|
return k.sendStarted(context)
|
||||||
|
case context.Commit.Status == model.StatusSuccess:
|
||||||
|
return k.sendSuccess(context)
|
||||||
|
case context.Commit.Status == model.StatusFailure:
|
||||||
|
return k.sendFailure(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KatoIM) getMessage(context *model.Request, message string) string {
|
||||||
|
url := getBuildUrl(context)
|
||||||
|
return fmt.Sprintf(message, context.Repo.Name, context.Commit.ShaShort(), url, context.Commit.Author)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendStarted disabled by default
|
||||||
|
func (k *KatoIM) sendStarted(context *model.Request) error {
|
||||||
|
switch k.Started {
|
||||||
|
case NotifyTrue, NotifyAlways, NotifyOn:
|
||||||
|
return k.send(k.getMessage(context, katoimStartedMessage), "yellow")
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendSuccess enabled by default
|
||||||
|
func (k *KatoIM) sendSuccess(context *model.Request) error {
|
||||||
|
switch k.Success {
|
||||||
|
case NotifyFalse, NotifyNever, NotifyOff:
|
||||||
|
return nil
|
||||||
|
case NotifyTrue, NotifyAlways, NotifyOn, "":
|
||||||
|
return k.send(k.getMessage(context, katoimSuccessMessage), "green")
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendFailure enabled by default
|
||||||
|
func (k *KatoIM) sendFailure(context *model.Request) error {
|
||||||
|
switch k.Failure {
|
||||||
|
case NotifyFalse, NotifyNever, NotifyOff:
|
||||||
|
return nil
|
||||||
|
case NotifyTrue, NotifyAlways, NotifyOn, "":
|
||||||
|
return k.send(k.getMessage(context, katoimFailureMessage), "red")
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to send HTTP requests
|
||||||
|
func (k *KatoIM) send(msg, color string) error {
|
||||||
|
// data will get posted in this format
|
||||||
|
data := struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
Renderer string `json:"renderer"`
|
||||||
|
From string `json:"from"`
|
||||||
|
}{msg, color, "markdown", "Drone"}
|
||||||
|
|
||||||
|
// data json encoded
|
||||||
|
payload, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send payload
|
||||||
|
url := fmt.Sprintf(katoimEndpoint, k.RoomID)
|
||||||
|
|
||||||
|
// create headers
|
||||||
|
headers := make(map[string]string)
|
||||||
|
headers["Accept"] = "application/json"
|
||||||
|
|
||||||
|
return sendJson(url, payload, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBuildUrl(context *model.Request) string {
|
||||||
|
return fmt.Sprintf("%s/%s/%s/%s/%s/%s", context.Host, context.Repo.Host, context.Repo.Owner, context.Repo.Name, context.Commit.Branch, context.Commit.Sha)
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper fuction to sent HTTP Post requests
|
||||||
|
// with JSON data as the payload.
|
||||||
|
func sendJson(url string, payload []byte, headers map[string]string) error {
|
||||||
|
client := &http.Client{}
|
||||||
|
buf := bytes.NewBuffer(payload)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", url, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
if headers != nil {
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Add(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/drone/drone/plugin/notify/email"
|
"github.com/drone/drone/plugin/notify/email"
|
||||||
"github.com/drone/drone/plugin/notify/github"
|
"github.com/drone/drone/plugin/notify/github"
|
||||||
"github.com/drone/drone/plugin/notify/irc"
|
"github.com/drone/drone/plugin/notify/irc"
|
||||||
|
"github.com/drone/drone/plugin/notify/katoim"
|
||||||
"github.com/drone/drone/plugin/notify/webhook"
|
"github.com/drone/drone/plugin/notify/webhook"
|
||||||
"github.com/drone/drone/shared/model"
|
"github.com/drone/drone/shared/model"
|
||||||
)
|
)
|
||||||
|
@ -28,6 +29,7 @@ type Notification struct {
|
||||||
Slack *Slack `yaml:"slack,omitempty"`
|
Slack *Slack `yaml:"slack,omitempty"`
|
||||||
Gitter *Gitter `yaml:"gitter,omitempty"`
|
Gitter *Gitter `yaml:"gitter,omitempty"`
|
||||||
Flowdock *Flowdock `yaml:"flowdock,omitempty"`
|
Flowdock *Flowdock `yaml:"flowdock,omitempty"`
|
||||||
|
KatoIM *katoim.KatoIM `yaml:"katoim,omitempty"`
|
||||||
|
|
||||||
GitHub github.GitHub `yaml:"--"`
|
GitHub github.GitHub `yaml:"--"`
|
||||||
}
|
}
|
||||||
|
@ -89,6 +91,14 @@ func (n *Notification) Send(context *model.Request) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send kato-im notifications
|
||||||
|
if n.KatoIM != nil {
|
||||||
|
err := n.KatoIM.Send(context)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// send email notifications
|
// send email notifications
|
||||||
// TODO (bradrydzewski) need to improve this code
|
// TODO (bradrydzewski) need to improve this code
|
||||||
githubStatus := new(github.GitHub)
|
githubStatus := new(github.GitHub)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
slackEndpoint = "https://%s.slack.com/services/hooks/incoming-webhook?token=%s"
|
|
||||||
slackStartedMessage = "*Building* <%s|%s> (%s) by %s"
|
slackStartedMessage = "*Building* <%s|%s> (%s) by %s"
|
||||||
slackStartedFallbackMessage = "Building %s (%s) by %s"
|
slackStartedFallbackMessage = "Building %s (%s) by %s"
|
||||||
slackSuccessMessage = "*Success* <%s|%s> (%s) by %s"
|
slackSuccessMessage = "*Success* <%s|%s> (%s) by %s"
|
||||||
|
@ -18,13 +17,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Slack struct {
|
type Slack struct {
|
||||||
Team string `yaml:"team,omitempty"`
|
WebhookUrl string `yaml:"webhook_url,omitempty"`
|
||||||
Channel string `yaml:"channel,omitempty"`
|
Channel string `yaml:"channel,omitempty"`
|
||||||
Username string `yaml:"username,omitempty"`
|
Username string `yaml:"username,omitempty"`
|
||||||
Token string `yaml:"token,omitempty"`
|
Started bool `yaml:"on_started,omitempty"`
|
||||||
Started bool `yaml:"on_started,omitempty"`
|
Success bool `yaml:"on_success,omitempty"`
|
||||||
Success bool `yaml:"on_success,omitempty"`
|
Failure bool `yaml:"on_failure,omitempty"`
|
||||||
Failure bool `yaml:"on_failure,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Slack) Send(context *model.Request) error {
|
func (s *Slack) Send(context *model.Request) error {
|
||||||
|
@ -100,10 +98,7 @@ func (s *Slack) send(msg string, fallback string, color string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// send payload
|
go sendJson(s.WebhookUrl, payload, nil)
|
||||||
url := fmt.Sprintf(slackEndpoint, s.Team, s.Token)
|
|
||||||
|
|
||||||
go sendJson(url, payload, nil)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,37 @@
|
||||||
package publish
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/drone/drone/plugin/condition"
|
||||||
|
"github.com/drone/drone/shared/build/buildfile"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dropbox struct {
|
||||||
|
AccessToken string `yaml:"access_token,omitempty"`
|
||||||
|
|
||||||
|
Source string `yaml:"source,omitempty"`
|
||||||
|
Target string `yaml:"target,omitempty"`
|
||||||
|
|
||||||
|
Condition *condition.Condition `yaml:"when,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dropbox) Write(f *buildfile.Buildfile) {
|
||||||
|
|
||||||
|
if len(d.AccessToken) == 0 || len(d.Source) == 0 || len(d.Target) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(d.Target, "/") {
|
||||||
|
d.Target = d.Target[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
f.WriteCmdSilent("echo 'publishing to Dropbox ...'")
|
||||||
|
|
||||||
|
cmd := "curl --upload-file %s -H \"Authorization: Bearer %s\" \"https://api-content.dropbox.com/1/files_put/auto/%s?overwrite=true\""
|
||||||
|
f.WriteCmd(fmt.Sprintf(cmd, d.Source, d.AccessToken, d.Target))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dropbox) GetCondition() *condition.Condition {
|
||||||
|
return d.Condition
|
||||||
|
}
|
||||||
|
|
|
@ -11,12 +11,13 @@ import (
|
||||||
// for publishing build artifacts when
|
// for publishing build artifacts when
|
||||||
// a Build has succeeded
|
// a Build has succeeded
|
||||||
type Publish struct {
|
type Publish struct {
|
||||||
S3 *S3 `yaml:"s3,omitempty"`
|
S3 *S3 `yaml:"s3,omitempty"`
|
||||||
Swift *Swift `yaml:"swift,omitempty"`
|
Swift *Swift `yaml:"swift,omitempty"`
|
||||||
PyPI *PyPI `yaml:"pypi,omitempty"`
|
PyPI *PyPI `yaml:"pypi,omitempty"`
|
||||||
NPM *npm.NPM `yaml:"npm,omitempty"`
|
NPM *npm.NPM `yaml:"npm,omitempty"`
|
||||||
Docker *Docker `yaml:"docker,omitempty"`
|
Docker *Docker `yaml:"docker,omitempty"`
|
||||||
Github *Github `yaml:"github,omitempty"`
|
Github *Github `yaml:"github,omitempty"`
|
||||||
|
Dropbox *Dropbox `yaml:"dropbox,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
|
func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
|
||||||
|
@ -49,6 +50,11 @@ func (p *Publish) Write(f *buildfile.Buildfile, r *repo.Repo) {
|
||||||
if p.Docker != nil && match(p.Docker.GetCondition(), r) {
|
if p.Docker != nil && match(p.Docker.GetCondition(), r) {
|
||||||
p.Docker.Write(f)
|
p.Docker.Write(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dropbox
|
||||||
|
if p.Dropbox != nil && match(p.Dropbox.GetCondition(), r) {
|
||||||
|
p.Dropbox.Write(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func match(c *condition.Condition, r *repo.Repo) bool {
|
func match(c *condition.Condition, r *repo.Repo) bool {
|
||||||
|
|
|
@ -11,11 +11,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Gitlab struct {
|
type Gitlab struct {
|
||||||
url string
|
url string
|
||||||
|
SkipVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(url string) *Gitlab {
|
func New(url string, skipVerify bool) *Gitlab {
|
||||||
return &Gitlab{url: url}
|
return &Gitlab{
|
||||||
|
url: url,
|
||||||
|
SkipVerify: skipVerify,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorize handles authentication with thrid party remote systems,
|
// Authorize handles authentication with thrid party remote systems,
|
||||||
|
@ -24,7 +28,7 @@ func (r *Gitlab) Authorize(res http.ResponseWriter, req *http.Request) (*model.L
|
||||||
var username = req.FormValue("username")
|
var username = req.FormValue("username")
|
||||||
var password = req.FormValue("password")
|
var password = req.FormValue("password")
|
||||||
|
|
||||||
var client = NewClient(r.url, "")
|
var client = NewClient(r.url, "", r.SkipVerify)
|
||||||
var session, err = client.GetSession(username, password)
|
var session, err = client.GetSession(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -55,7 +59,7 @@ func (r *Gitlab) GetHost() string {
|
||||||
func (r *Gitlab) GetRepos(user *model.User) ([]*model.Repo, error) {
|
func (r *Gitlab) GetRepos(user *model.User) ([]*model.Repo, error) {
|
||||||
|
|
||||||
var repos []*model.Repo
|
var repos []*model.Repo
|
||||||
var client = NewClient(r.url, user.Access)
|
var client = NewClient(r.url, user.Access, r.SkipVerify)
|
||||||
var list, err = client.AllProjects()
|
var list, err = client.AllProjects()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -110,7 +114,7 @@ func (r *Gitlab) GetRepos(user *model.User) ([]*model.Repo, error) {
|
||||||
// GetScript fetches the build script (.drone.yml) from the remote
|
// GetScript fetches the build script (.drone.yml) from the remote
|
||||||
// repository and returns in string format.
|
// repository and returns in string format.
|
||||||
func (r *Gitlab) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
|
func (r *Gitlab) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
|
||||||
var client = NewClient(r.url, user.Access)
|
var client = NewClient(r.url, user.Access, r.SkipVerify)
|
||||||
var path = ns(repo.Owner, repo.Name)
|
var path = ns(repo.Owner, repo.Name)
|
||||||
return client.RepoRawFile(path, hook.Sha, ".drone.yml")
|
return client.RepoRawFile(path, hook.Sha, ".drone.yml")
|
||||||
}
|
}
|
||||||
|
@ -118,7 +122,7 @@ func (r *Gitlab) GetScript(user *model.User, repo *model.Repo, hook *model.Hook)
|
||||||
// Activate activates a repository by adding a Post-commit hook and
|
// Activate activates a repository by adding a Post-commit hook and
|
||||||
// a Public Deploy key, if applicable.
|
// a Public Deploy key, if applicable.
|
||||||
func (r *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error {
|
func (r *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error {
|
||||||
var client = NewClient(r.url, user.Access)
|
var client = NewClient(r.url, user.Access, r.SkipVerify)
|
||||||
var path = ns(repo.Owner, repo.Name)
|
var path = ns(repo.Owner, repo.Name)
|
||||||
var title, err = GetKeyTitle(link)
|
var title, err = GetKeyTitle(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -14,7 +14,7 @@ func Test_Github(t *testing.T) {
|
||||||
var server = testdata.NewServer()
|
var server = testdata.NewServer()
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
var gitlab = New(server.URL)
|
var gitlab = New(server.URL, false)
|
||||||
var user = model.User{
|
var user = model.User{
|
||||||
Access: "e3b0c44298fc1c149afbf4c8996fb",
|
Access: "e3b0c44298fc1c149afbf4c8996fb",
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
|
|
||||||
// NewClient is a helper function that returns a new GitHub
|
// NewClient is a helper function that returns a new GitHub
|
||||||
// client using the provided OAuth token.
|
// client using the provided OAuth token.
|
||||||
func NewClient(uri, token string) *gogitlab.Gitlab {
|
func NewClient(uri, token string, skipVerify bool) *gogitlab.Gitlab {
|
||||||
return gogitlab.NewGitlab(uri, "/api/v3", token)
|
return gogitlab.NewGitlabCert(uri, "/api/v3", token, skipVerify)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRead is a helper function that returns true if the
|
// IsRead is a helper function that returns true if the
|
||||||
|
|
|
@ -6,7 +6,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gitlabURL = config.String("gitlab-url", "")
|
gitlabURL = config.String("gitlab-url", "")
|
||||||
|
gitlabSkipVerify = config.Bool("gitlab-skip-verify", false)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Registers the Gitlab plugin using the default
|
// Registers the Gitlab plugin using the default
|
||||||
|
@ -17,6 +18,9 @@ func Register() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
remote.Register(
|
remote.Register(
|
||||||
New(*gitlabURL),
|
New(
|
||||||
|
*gitlabURL,
|
||||||
|
*gitlabSkipVerify,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
183
plugin/remote/gogs/gogs.go
Normal file
183
plugin/remote/gogs/gogs.go
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package gogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/drone/drone/shared/model"
|
||||||
|
"github.com/gogits/go-gogs-client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gogs struct {
|
||||||
|
URL string
|
||||||
|
Secret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(url string, secret string) *Gogs {
|
||||||
|
return &Gogs{URL: url, Secret: secret}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorize handles Gogs authorization
|
||||||
|
func (r *Gogs) Authorize(res http.ResponseWriter, req *http.Request) (*model.Login, error) {
|
||||||
|
var username = req.FormValue("username")
|
||||||
|
var password = req.FormValue("password")
|
||||||
|
var client = gogs.NewClient(r.URL, "")
|
||||||
|
|
||||||
|
// try to fetch drone token if it exists
|
||||||
|
var accessToken = ""
|
||||||
|
tokens, err := client.ListAccessTokens(username, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, token := range tokens {
|
||||||
|
if token.Name == "drone" {
|
||||||
|
accessToken = token.Sha1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if drone token not found, create it
|
||||||
|
if accessToken == "" {
|
||||||
|
token, err := client.CreateAccessToken(username, password, gogs.CreateAccessTokenOption{Name: "drone"})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
accessToken = token.Sha1
|
||||||
|
}
|
||||||
|
|
||||||
|
// update client
|
||||||
|
client = gogs.NewClient(r.URL, accessToken)
|
||||||
|
|
||||||
|
// fetch user information
|
||||||
|
user, err := client.GetUserInfo(username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var login = new(model.Login)
|
||||||
|
login.Name = user.FullName
|
||||||
|
login.Email = user.Email
|
||||||
|
login.Access = accessToken
|
||||||
|
login.Login = username
|
||||||
|
return login, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKind returns the internal identifier of this remote Gogs instance
|
||||||
|
func (r *Gogs) GetKind() string {
|
||||||
|
return model.RemoteGogs
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHost returns the hostname of this remote Gogs instance
|
||||||
|
func (r *Gogs) GetHost() string {
|
||||||
|
uri, _ := url.Parse(r.URL)
|
||||||
|
return uri.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepos fetches all repositories that the specified
|
||||||
|
// user has access to in the remote system.
|
||||||
|
func (r *Gogs) GetRepos(user *model.User) ([]*model.Repo, error) {
|
||||||
|
var repos []*model.Repo
|
||||||
|
|
||||||
|
var remote = r.GetKind()
|
||||||
|
var hostname = r.GetHost()
|
||||||
|
var client = gogs.NewClient(r.URL, user.Access)
|
||||||
|
|
||||||
|
gogsRepos, err := client.ListMyRepos()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, repo := range gogsRepos {
|
||||||
|
var repoName = strings.Split(repo.FullName, "/")
|
||||||
|
if len(repoName) < 2 {
|
||||||
|
log.Println("invalid repo full_name", repo.FullName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var owner = repoName[0]
|
||||||
|
var name = repoName[1]
|
||||||
|
|
||||||
|
var repo = model.Repo{
|
||||||
|
UserID: user.ID,
|
||||||
|
Remote: remote,
|
||||||
|
Host: hostname,
|
||||||
|
Owner: owner,
|
||||||
|
Name: name,
|
||||||
|
Private: repo.Private,
|
||||||
|
CloneURL: repo.CloneUrl,
|
||||||
|
GitURL: repo.CloneUrl,
|
||||||
|
SSHURL: repo.SshUrl,
|
||||||
|
URL: repo.HtmlUrl,
|
||||||
|
Role: &model.Perm{
|
||||||
|
Admin: repo.Permissions.Admin,
|
||||||
|
Write: repo.Permissions.Push,
|
||||||
|
Read: repo.Permissions.Pull,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
repos = append(repos, &repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return repos, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetScript fetches the build script (.drone.yml) from the remote
|
||||||
|
// repository and returns a byte array
|
||||||
|
func (r *Gogs) GetScript(user *model.User, repo *model.Repo, hook *model.Hook) ([]byte, error) {
|
||||||
|
var client = gogs.NewClient(r.URL, user.Access)
|
||||||
|
return client.GetFile(repo.Owner, repo.Name, hook.Sha, ".drone.yml")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate activates a repository
|
||||||
|
func (r *Gogs) Activate(user *model.User, repo *model.Repo, link string) error {
|
||||||
|
var client = gogs.NewClient(r.URL, user.Access)
|
||||||
|
|
||||||
|
var config = map[string]string{
|
||||||
|
"url": link,
|
||||||
|
"secret": r.Secret,
|
||||||
|
"content_type": "json",
|
||||||
|
}
|
||||||
|
var hook = gogs.CreateHookOption{
|
||||||
|
Type: "gogs",
|
||||||
|
Config: config,
|
||||||
|
Active: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := client.CreateRepoHook(repo.Owner, repo.Name, hook)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseHook parses the post-commit hook from the Request body
|
||||||
|
// and returns the required data in a standard format.
|
||||||
|
func (r *Gogs) ParseHook(req *http.Request) (*model.Hook, error) {
|
||||||
|
defer req.Body.Close()
|
||||||
|
var payloadbytes, _ = ioutil.ReadAll(req.Body)
|
||||||
|
var payload, err = gogs.ParseHook(payloadbytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the payload has the minimum amount of required data.
|
||||||
|
if payload.Repo == nil || payload.Commits == nil || len(payload.Commits) == 0 {
|
||||||
|
return nil, fmt.Errorf("Invalid Gogs post-commit Hook. Missing Repo or Commit data.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if payload.Secret != r.Secret {
|
||||||
|
return nil, fmt.Errorf("Payload secret does not match stored secret")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.Hook{
|
||||||
|
Owner: payload.Repo.Owner.UserName,
|
||||||
|
Repo: payload.Repo.Name,
|
||||||
|
Sha: payload.Commits[0].Id,
|
||||||
|
Branch: payload.Branch(),
|
||||||
|
Author: payload.Commits[0].Author.UserName,
|
||||||
|
Timestamp: time.Now().UTC().String(),
|
||||||
|
Message: payload.Commits[0].Message,
|
||||||
|
}, nil
|
||||||
|
}
|
23
plugin/remote/gogs/register.go
Normal file
23
plugin/remote/gogs/register.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package gogs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/config"
|
||||||
|
"github.com/drone/drone/plugin/remote"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
gogsUrl = config.String("gogs-url", "")
|
||||||
|
gogsSecret = config.String("gogs-secret", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Registers the Gogs plugin using the default
|
||||||
|
// settings from the config file or environment
|
||||||
|
// variables.
|
||||||
|
func Register() {
|
||||||
|
if len(*gogsUrl) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remote.Register(
|
||||||
|
New(*gogsUrl, *gogsSecret),
|
||||||
|
)
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
User-agent: *
|
User-agent: *
|
||||||
|
|
|
@ -52,6 +52,10 @@ app.config(['$routeProvider', '$locationProvider', '$httpProvider', function($ro
|
||||||
templateUrl: '/static/views/login_gitlab.html',
|
templateUrl: '/static/views/login_gitlab.html',
|
||||||
title: 'GitLab Login',
|
title: 'GitLab Login',
|
||||||
})
|
})
|
||||||
|
.when('/gogs', {
|
||||||
|
templateUrl: '/static/views/login_gogs.html',
|
||||||
|
title: 'Gogs Setup',
|
||||||
|
})
|
||||||
.when('/setup', {
|
.when('/setup', {
|
||||||
templateUrl: '/static/views/setup.html',
|
templateUrl: '/static/views/setup.html',
|
||||||
controller: 'SetupController',
|
controller: 'SetupController',
|
||||||
|
@ -234,6 +238,6 @@ app.controller("AccountReposController", function($scope, $http, $location, user
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
$scope.byRemote = function(entry){
|
$scope.byRemote = function(entry){
|
||||||
return $scope.remote == "" || $scope.remote == entry.remote;
|
return $scope.remote == "" || $scope.remote == entry.remote;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,6 +30,9 @@ angular.module('app').controller("ConfigController", function($scope, $http, rem
|
||||||
case 'stash.atlassian.com':
|
case 'stash.atlassian.com':
|
||||||
$scope.stash = remote;
|
$scope.stash = remote;
|
||||||
break;
|
break;
|
||||||
|
case 'gogs':
|
||||||
|
$scope.gogs = remote;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -144,6 +144,7 @@
|
||||||
case 'enterprise.github.com' : return 'GitHub Enterprise';
|
case 'enterprise.github.com' : return 'GitHub Enterprise';
|
||||||
case 'bitbucket.org' : return 'Bitbucket';
|
case 'bitbucket.org' : return 'Bitbucket';
|
||||||
case 'stash.atlassian.com' : return 'Atlassian Stash';
|
case 'stash.atlassian.com' : return 'Atlassian Stash';
|
||||||
|
case 'gogs' : return 'Gogs';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +161,7 @@
|
||||||
case 'enterprise.github.com' : return 'fa-github-square';
|
case 'enterprise.github.com' : return 'fa-github-square';
|
||||||
case 'bitbucket.org' : return 'fa-bitbucket-square';
|
case 'bitbucket.org' : return 'fa-bitbucket-square';
|
||||||
case 'stash.atlassian.com' : return 'fa-bitbucket-square';
|
case 'stash.atlassian.com' : return 'fa-bitbucket-square';
|
||||||
|
case 'gogs' : return 'fa-git-square';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,4 +205,4 @@
|
||||||
.filter('toDuration', toDuration)
|
.filter('toDuration', toDuration)
|
||||||
.filter('unique', unique);
|
.filter('unique', unique);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -16,8 +16,17 @@
|
||||||
</strong>
|
</strong>
|
||||||
</dd>
|
</dd>
|
||||||
<!-- /BITBUCKET -->
|
<!-- /BITBUCKET -->
|
||||||
|
<!-- GOGS -->
|
||||||
|
<dd class="large" ng-if="repo.remote == 'gogs' ">
|
||||||
|
<strong>
|
||||||
|
commit
|
||||||
|
<a href="{{ repo.url }}/commit/{{ commit.sha }}" >{{ commit.sha | shortHash}}</a>
|
||||||
|
to <a href="{{ repo.url }}/src/{{ commit.branch }}">{{ commit.branch }}</a> branch
|
||||||
|
</strong>
|
||||||
|
</dd>
|
||||||
|
<!-- /GOGS -->
|
||||||
<!-- STASH -->
|
<!-- STASH -->
|
||||||
<dd class="large" ng-if="repo.remote != 'gitlab.com' && repo.remote != 'github.com' && repo.remote != 'enterprise.github.com' && repo.remote != 'bitbucket.org' ">
|
<dd class="large" ng-if="repo.remote != 'gitlab.com' && repo.remote != 'github.com' && repo.remote != 'enterprise.github.com' && repo.remote != 'bitbucket.org' && repo.remote != 'gogs' ">
|
||||||
<strong>commit <u>{{ commit.sha | shortHash}}</u> to <u>{{ commit.branch }}</u> branch</strong>
|
<strong>commit <u>{{ commit.sha | shortHash}}</u> to <u>{{ commit.branch }}</u> branch</strong>
|
||||||
</dd>
|
</dd>
|
||||||
<!-- /STASH -->
|
<!-- /STASH -->
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="remote.type != 'github.com' && remote.type != 'bitbucket.org' ">
|
<div ng-if="remote.type != 'github.com' && remote.type != 'bitbucket.org' && remote.type != 'gogs' ">
|
||||||
<label>API URL</label>
|
<label>API URL</label>
|
||||||
<div ng-switch="remote.type">
|
<div ng-switch="remote.type">
|
||||||
<input ng-switch-default ng-model="remote.api" type="text" placeholder="https://www.foo.com/api" />
|
<input ng-switch-default ng-model="remote.api" type="text" placeholder="https://www.foo.com/api" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="remote.type != 'gitlab.com'">
|
<div ng-if="remote.type != 'gitlab.com' && remote.type != 'gogs' ">
|
||||||
<label>OAuth Client</label>
|
<label>OAuth Client</label>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" ng-model="remote.client" />
|
<input type="text" ng-model="remote.client" />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!--
|
<!--
|
||||||
minor modifications to the style that only apply to this view
|
minor modifications to the style that only apply to this view
|
||||||
-->
|
-->
|
||||||
<style>
|
<style>
|
||||||
|
@ -11,12 +11,15 @@ minor modifications to the style that only apply to this view
|
||||||
<article id="loginpage">
|
<article id="loginpage">
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1" ng-if="state == 1 && remotes.length != 0" ng-repeat="remote in remotes">
|
<div class="pure-u-1" ng-if="state == 1 && remotes.length != 0" ng-repeat="remote in remotes">
|
||||||
<a ng-href="/api/auth/{{ remote.type }}" target="_self" ng-if="remote.type != 'gitlab.com' ">
|
<a ng-href="/api/auth/{{ remote.type }}" target="_self" ng-if="remote.type != 'gitlab.com' && remote.type != 'gogs' ">
|
||||||
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
||||||
</a>
|
</a>
|
||||||
<a ng-href="/gitlab" ng-if="remote.type == 'gitlab.com' ">
|
<a ng-href="/gitlab" ng-if="remote.type == 'gitlab.com' ">
|
||||||
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
||||||
</a>
|
</a>
|
||||||
|
<a ng-href="/gogs" ng-if="remote.type == 'gogs' ">
|
||||||
|
<i class="fa {{ remote.type | remoteIcon }}"></i> {{ remote.type | remoteName }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-u-1" ng-if="state == 1 && remotes.length == 0">
|
<div class="pure-u-1" ng-if="state == 1 && remotes.length == 0">
|
||||||
|
@ -25,4 +28,4 @@ minor modifications to the style that only apply to this view
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
23
server/app/views/login_gogs.html
Normal file
23
server/app/views/login_gogs.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<!--
|
||||||
|
minor modifications to the style that only apply to this view
|
||||||
|
-->
|
||||||
|
<style>
|
||||||
|
#container { padding-top: 155px; }
|
||||||
|
#header { height: 150px; }
|
||||||
|
#header .user { display:none; }
|
||||||
|
#header .brand { margin-top:55px ; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<article id="loginpage">
|
||||||
|
<form class="pure-g" method="POST" action="/api/auth/gogs">
|
||||||
|
<div class="pure-u-1">
|
||||||
|
<input type="text" name="username" placeholder="Username" />
|
||||||
|
</div>
|
||||||
|
<div class="pure-u-1">
|
||||||
|
<input type="password" name="password" placeholder="Password" />
|
||||||
|
</div>
|
||||||
|
<div class="pure-u-1">
|
||||||
|
<input type="submit" value="Gogs Login" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
|
@ -25,6 +25,7 @@
|
||||||
<option value="gitlab.com">GitLab</option>
|
<option value="gitlab.com">GitLab</option>
|
||||||
<option value="bitbucket.org">Bitbucket</option>
|
<option value="bitbucket.org">Bitbucket</option>
|
||||||
<option value="stash.atlassian.com">Stash</option>
|
<option value="stash.atlassian.com">Stash</option>
|
||||||
|
<option value="gogs">Gogs</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="username">Username</label>
|
<label for="username">Username</label>
|
||||||
|
@ -35,4 +36,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -122,7 +122,7 @@ WHERE c.repo_id = r.repo_id
|
||||||
AND r.repo_id = p.repo_id
|
AND r.repo_id = p.repo_id
|
||||||
AND p.user_id = ?
|
AND p.user_id = ?
|
||||||
GROUP BY r.repo_id
|
GROUP BY r.repo_id
|
||||||
) ORDER BY c.commit_created DESC LIMIT 5;
|
) ORDER BY c.commit_created DESC;
|
||||||
`
|
`
|
||||||
|
|
||||||
// SQL query to retrieve the ungrouped, latest Commits
|
// SQL query to retrieve the ungrouped, latest Commits
|
||||||
|
@ -144,7 +144,7 @@ LIMIT 20
|
||||||
const commitListQuery = `
|
const commitListQuery = `
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM commits
|
FROM commits
|
||||||
WHERE repo_id = ?
|
WHERE repo_id = ?
|
||||||
ORDER BY commit_id DESC
|
ORDER BY commit_id DESC
|
||||||
LIMIT 20
|
LIMIT 20
|
||||||
`
|
`
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/drone/drone/plugin/remote/bitbucket"
|
"github.com/drone/drone/plugin/remote/bitbucket"
|
||||||
"github.com/drone/drone/plugin/remote/github"
|
"github.com/drone/drone/plugin/remote/github"
|
||||||
"github.com/drone/drone/plugin/remote/gitlab"
|
"github.com/drone/drone/plugin/remote/gitlab"
|
||||||
|
"github.com/drone/drone/plugin/remote/gogs"
|
||||||
"github.com/drone/drone/server/blobstore"
|
"github.com/drone/drone/server/blobstore"
|
||||||
"github.com/drone/drone/server/capability"
|
"github.com/drone/drone/server/capability"
|
||||||
"github.com/drone/drone/server/datastore"
|
"github.com/drone/drone/server/datastore"
|
||||||
|
@ -33,6 +34,10 @@ import (
|
||||||
"github.com/drone/drone/server/worker/pool"
|
"github.com/drone/drone/server/worker/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DockerTLSWarning = `WARINING: Docker TLS cert or key not given, this may cause a build errors`
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// commit sha for the current build, set by
|
// commit sha for the current build, set by
|
||||||
// the compile process.
|
// the compile process.
|
||||||
|
@ -60,9 +65,9 @@ var (
|
||||||
pub *pubsub.PubSub
|
pub *pubsub.PubSub
|
||||||
|
|
||||||
// Docker configuration details.
|
// Docker configuration details.
|
||||||
dockercrt = config.String("docker-cert", "")
|
dockercert = config.String("docker-cert", "")
|
||||||
dockerkey = config.String("docker-key", "")
|
dockerkey = config.String("docker-key", "")
|
||||||
nodes StringArr
|
nodes StringArr
|
||||||
|
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
|
||||||
|
@ -97,6 +102,7 @@ func main() {
|
||||||
bitbucket.Register()
|
bitbucket.Register()
|
||||||
github.Register()
|
github.Register()
|
||||||
gitlab.Register()
|
gitlab.Register()
|
||||||
|
gogs.Register()
|
||||||
|
|
||||||
caps = map[string]bool{}
|
caps = map[string]bool{}
|
||||||
caps[capability.Registration] = *open
|
caps[capability.Registration] = *open
|
||||||
|
@ -115,7 +121,14 @@ func main() {
|
||||||
workers.Allocate(docker.New())
|
workers.Allocate(docker.New())
|
||||||
} else {
|
} else {
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
workers.Allocate(docker.NewHost(node))
|
if strings.HasPrefix(node, "unix://") {
|
||||||
|
workers.Allocate(docker.NewHost(node))
|
||||||
|
} else if *dockercert != "" && *dockerkey != "" {
|
||||||
|
workers.Allocate(docker.NewHostCertFile(node, *dockercert, *dockerkey))
|
||||||
|
} else {
|
||||||
|
fmt.Println(DockerTLSWarning)
|
||||||
|
workers.Allocate(docker.NewHost(node))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +137,7 @@ func main() {
|
||||||
// create handler for static resources
|
// create handler for static resources
|
||||||
assets := rice.MustFindBox("app").HTTPBox()
|
assets := rice.MustFindBox("app").HTTPBox()
|
||||||
assetserve := http.FileServer(rice.MustFindBox("app").HTTPBox())
|
assetserve := http.FileServer(rice.MustFindBox("app").HTTPBox())
|
||||||
|
http.Handle("/robots.txt", assetserve)
|
||||||
http.Handle("/static/", http.StripPrefix("/static", assetserve))
|
http.Handle("/static/", http.StripPrefix("/static", assetserve))
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write(assets.MustBytes("index.html"))
|
w.Write(assets.MustBytes("index.html"))
|
||||||
|
|
|
@ -49,6 +49,20 @@ func NewHost(host string) *Docker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewHostCertFile(host, cert, key string) *Docker {
|
||||||
|
docker_node, err := docker.NewHostCertFile(host, cert, key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Docker{
|
||||||
|
UUID: uuid.New(),
|
||||||
|
Kind: dockerKind,
|
||||||
|
Created: time.Now().UTC().Unix(),
|
||||||
|
docker: docker_node,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Docker) Do(c context.Context, r *worker.Work) {
|
func (d *Docker) Do(c context.Context, r *worker.Work) {
|
||||||
|
|
||||||
// ensure that we can recover from any panics to
|
// ensure that we can recover from any panics to
|
||||||
|
|
|
@ -218,10 +218,6 @@ func (b *Builder) setup() error {
|
||||||
b.services = append(b.services, info)
|
b.services = append(b.services, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.writeIdentifyFile(dir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.writeBuildScript(dir); err != nil {
|
if err := b.writeBuildScript(dir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -274,6 +270,8 @@ func (b *Builder) setup() error {
|
||||||
// and the supporting service containers.
|
// and the supporting service containers.
|
||||||
func (b *Builder) teardown() error {
|
func (b *Builder) teardown() error {
|
||||||
|
|
||||||
|
defer b.dockerClient.CloseIdleConnections()
|
||||||
|
|
||||||
// stop and destroy the container
|
// stop and destroy the container
|
||||||
if b.container != nil {
|
if b.container != nil {
|
||||||
|
|
||||||
|
@ -319,6 +317,7 @@ func (b *Builder) teardown() error {
|
||||||
func (b *Builder) run() error {
|
func (b *Builder) run() error {
|
||||||
// create and run the container
|
// create and run the container
|
||||||
conf := docker.Config{
|
conf := docker.Config{
|
||||||
|
Hostname: script.DockerHostname(b.Build.Docker),
|
||||||
Image: b.image.ID,
|
Image: b.image.ID,
|
||||||
AttachStdin: false,
|
AttachStdin: false,
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
|
@ -449,31 +448,16 @@ func (b *Builder) writeDockerfile(dir string) error {
|
||||||
// is the "ubuntu" user, since all build images
|
// is the "ubuntu" user, since all build images
|
||||||
// inherit from the ubuntu cloud ISO
|
// inherit from the ubuntu cloud ISO
|
||||||
dockerfile.WriteUser("ubuntu")
|
dockerfile.WriteUser("ubuntu")
|
||||||
dockerfile.WriteEnv("HOME", "/home/ubuntu")
|
|
||||||
dockerfile.WriteEnv("LANG", "en_US.UTF-8")
|
|
||||||
dockerfile.WriteEnv("LANGUAGE", "en_US:en")
|
|
||||||
dockerfile.WriteEnv("LOGNAME", "ubuntu")
|
dockerfile.WriteEnv("LOGNAME", "ubuntu")
|
||||||
dockerfile.WriteEnv("TERM", "xterm")
|
dockerfile.WriteEnv("HOME", "/home/ubuntu")
|
||||||
dockerfile.WriteEnv("SHELL", "/bin/bash")
|
|
||||||
dockerfile.WriteAdd("id_rsa", "/home/ubuntu/.ssh/id_rsa")
|
|
||||||
dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /home/ubuntu/.ssh")
|
|
||||||
dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /var/cache/drone")
|
dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /var/cache/drone")
|
||||||
dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /usr/local/bin/drone")
|
dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /usr/local/bin/drone")
|
||||||
dockerfile.WriteRun("sudo chmod 600 /home/ubuntu/.ssh/id_rsa")
|
|
||||||
default:
|
default:
|
||||||
// all other images are assumed to use
|
// all other images are assumed to use
|
||||||
// the root user.
|
// the root user.
|
||||||
dockerfile.WriteUser("root")
|
dockerfile.WriteUser("root")
|
||||||
dockerfile.WriteEnv("HOME", "/root")
|
|
||||||
dockerfile.WriteEnv("LANG", "en_US.UTF-8")
|
|
||||||
dockerfile.WriteEnv("LANGUAGE", "en_US:en")
|
|
||||||
dockerfile.WriteEnv("LOGNAME", "root")
|
dockerfile.WriteEnv("LOGNAME", "root")
|
||||||
dockerfile.WriteEnv("TERM", "xterm")
|
dockerfile.WriteEnv("HOME", "/root")
|
||||||
dockerfile.WriteEnv("SHELL", "/bin/bash")
|
|
||||||
dockerfile.WriteEnv("GOPATH", "/var/cache/drone")
|
|
||||||
dockerfile.WriteAdd("id_rsa", "/root/.ssh/id_rsa")
|
|
||||||
dockerfile.WriteRun("chmod 600 /root/.ssh/id_rsa")
|
|
||||||
dockerfile.WriteRun("echo 'StrictHostKeyChecking no' > /root/.ssh/config")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerfile.WriteAdd("proxy.sh", "/etc/drone.d/")
|
dockerfile.WriteAdd("proxy.sh", "/etc/drone.d/")
|
||||||
|
@ -489,6 +473,13 @@ func (b *Builder) writeDockerfile(dir string) error {
|
||||||
func (b *Builder) writeBuildScript(dir string) error {
|
func (b *Builder) writeBuildScript(dir string) error {
|
||||||
f := buildfile.New()
|
f := buildfile.New()
|
||||||
|
|
||||||
|
// add environment variables for user env
|
||||||
|
f.WriteEnv("LANG", "en_US.UTF-8")
|
||||||
|
f.WriteEnv("LANGUAGE", "en_US:en")
|
||||||
|
f.WriteEnv("TERM", "xterm")
|
||||||
|
f.WriteEnv("GOPATH", "/var/cache/drone")
|
||||||
|
f.WriteEnv("SHELL", "/bin/bash")
|
||||||
|
|
||||||
// add environment variables about the build
|
// add environment variables about the build
|
||||||
f.WriteEnv("CI", "true")
|
f.WriteEnv("CI", "true")
|
||||||
f.WriteEnv("DRONE", "true")
|
f.WriteEnv("DRONE", "true")
|
||||||
|
@ -512,6 +503,8 @@ func (b *Builder) writeBuildScript(dir string) error {
|
||||||
f.WriteHost(mapping)
|
f.WriteHost(mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.WriteFile("$HOME/.ssh/id_rsa", b.Key, 600)
|
||||||
|
|
||||||
// if the repository is remote then we should
|
// if the repository is remote then we should
|
||||||
// add the commands to the build script to
|
// add the commands to the build script to
|
||||||
// clone the repository
|
// clone the repository
|
||||||
|
@ -554,11 +547,3 @@ func (b *Builder) writeProxyScript(dir string) error {
|
||||||
proxyfilePath := filepath.Join(dir, "proxy.sh")
|
proxyfilePath := filepath.Join(dir, "proxy.sh")
|
||||||
return ioutil.WriteFile(proxyfilePath, proxyfile.Bytes(), 0755)
|
return ioutil.WriteFile(proxyfilePath, proxyfile.Bytes(), 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeIdentifyFile is a helper function that
|
|
||||||
// will generate the id_rsa file in the builder's
|
|
||||||
// temp directory to be added to the Image.
|
|
||||||
func (b *Builder) writeIdentifyFile(dir string) error {
|
|
||||||
keyfilePath := filepath.Join(dir, "id_rsa")
|
|
||||||
return ioutil.WriteFile(keyfilePath, b.Key, 0700)
|
|
||||||
}
|
|
||||||
|
|
|
@ -477,26 +477,6 @@ func TestRunErrorWait(t *testing.T) {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteIdentifyFile(t *testing.T) {
|
|
||||||
// temporary directory to store file
|
|
||||||
dir, _ := ioutil.TempDir("", "drone-test-")
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
|
|
||||||
b := Builder{}
|
|
||||||
b.Key = []byte("ssh-rsa AAA...")
|
|
||||||
b.writeIdentifyFile(dir)
|
|
||||||
|
|
||||||
// persist a dummy id_rsa keyfile to disk
|
|
||||||
keyfile, err := ioutil.ReadFile(filepath.Join(dir, "id_rsa"))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected id_rsa file saved to disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(keyfile) != string(b.Key) {
|
|
||||||
t.Errorf("Expected id_rsa value saved as %s, got %s", b.Key, keyfile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWriteProxyScript(t *testing.T) {
|
func TestWriteProxyScript(t *testing.T) {
|
||||||
// temporary directory to store file
|
// temporary directory to store file
|
||||||
dir, _ := ioutil.TempDir("", "drone-test-")
|
dir, _ := ioutil.TempDir("", "drone-test-")
|
||||||
|
@ -541,6 +521,7 @@ func TestWriteBuildScript(t *testing.T) {
|
||||||
b := Builder{}
|
b := Builder{}
|
||||||
b.Build = &script.Build{
|
b.Build = &script.Build{
|
||||||
Hosts: []string{"127.0.0.1"}}
|
Hosts: []string{"127.0.0.1"}}
|
||||||
|
b.Key = []byte("ssh-rsa AAA...")
|
||||||
b.Repo = &repo.Repo{
|
b.Repo = &repo.Repo{
|
||||||
Path: "git://github.com/drone/drone.git",
|
Path: "git://github.com/drone/drone.git",
|
||||||
Branch: "master",
|
Branch: "master",
|
||||||
|
@ -556,6 +537,11 @@ func TestWriteBuildScript(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f := buildfile.New()
|
f := buildfile.New()
|
||||||
|
f.WriteEnv("LANG", "en_US.UTF-8")
|
||||||
|
f.WriteEnv("LANGUAGE", "en_US:en")
|
||||||
|
f.WriteEnv("TERM", "xterm")
|
||||||
|
f.WriteEnv("GOPATH", "/var/cache/drone")
|
||||||
|
f.WriteEnv("SHELL", "/bin/bash")
|
||||||
f.WriteEnv("CI", "true")
|
f.WriteEnv("CI", "true")
|
||||||
f.WriteEnv("DRONE", "true")
|
f.WriteEnv("DRONE", "true")
|
||||||
f.WriteEnv("DRONE_REMOTE", "git://github.com/drone/drone.git")
|
f.WriteEnv("DRONE_REMOTE", "git://github.com/drone/drone.git")
|
||||||
|
@ -570,6 +556,7 @@ func TestWriteBuildScript(t *testing.T) {
|
||||||
f.WriteEnv("CI_BRANCH", "master")
|
f.WriteEnv("CI_BRANCH", "master")
|
||||||
f.WriteEnv("CI_PULL_REQUEST", "123")
|
f.WriteEnv("CI_PULL_REQUEST", "123")
|
||||||
f.WriteHost("127.0.0.1")
|
f.WriteHost("127.0.0.1")
|
||||||
|
f.WriteFile("$HOME/.ssh/id_rsa", []byte("ssh-rsa AAA..."), 600)
|
||||||
f.WriteCmd("git clone --depth=0 --recursive git://github.com/drone/drone.git /var/cache/drone/github.com/drone/drone")
|
f.WriteCmd("git clone --depth=0 --recursive git://github.com/drone/drone.git /var/cache/drone/github.com/drone/drone")
|
||||||
f.WriteCmd("git fetch origin +refs/pull/123/head:refs/remotes/origin/pr/123")
|
f.WriteCmd("git fetch origin +refs/pull/123/head:refs/remotes/origin/pr/123")
|
||||||
f.WriteCmd("git checkout -qf -b pr/123 origin/pr/123")
|
f.WriteCmd("git checkout -qf -b pr/123 origin/pr/123")
|
||||||
|
|
|
@ -52,6 +52,12 @@ func (b *Buildfile) WriteHost(mapping string) {
|
||||||
b.WriteCmdSilent(fmt.Sprintf("[ -f /usr/bin/sudo ] && echo %q | sudo tee -a /etc/hosts", mapping))
|
b.WriteCmdSilent(fmt.Sprintf("[ -f /usr/bin/sudo ] && echo %q | sudo tee -a /etc/hosts", mapping))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteFile add files as part of the script.
|
||||||
|
func (b *Buildfile) WriteFile(path string, file []byte, i int) {
|
||||||
|
b.WriteString(fmt.Sprintf("echo '%s' | tee %s > /dev/null\n", string(file), path))
|
||||||
|
b.WriteCmdSilent(fmt.Sprintf("chmod %d %s", i, path))
|
||||||
|
}
|
||||||
|
|
||||||
// every build script starts with the following
|
// every build script starts with the following
|
||||||
// code at the start.
|
// code at the start.
|
||||||
var base = `
|
var base = `
|
||||||
|
@ -70,6 +76,13 @@ if [ -d /etc/drone.d ]; then
|
||||||
unset i
|
unset i
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ ! -d $HOME/.ssh ]; then
|
||||||
|
mkdir -p $HOME/.ssh
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 0700 $HOME/.ssh
|
||||||
|
echo 'StrictHostKeyChecking no' | tee $HOME/.ssh/config > /dev/null
|
||||||
|
|
||||||
# be sure to exit on error and print out
|
# be sure to exit on error and print out
|
||||||
# our bash commands, so we can which commands
|
# our bash commands, so we can which commands
|
||||||
# are executing and troubleshoot failures.
|
# are executing and troubleshoot failures.
|
||||||
|
|
|
@ -46,4 +46,11 @@ func TestWrite(t *testing.T) {
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("Exepected WriteHost returned %s, got %s", want, got)
|
t.Errorf("Exepected WriteHost returned %s, got %s", want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f = &Buildfile{}
|
||||||
|
f.WriteFile("$HOME/.ssh/id_rsa", []byte("ssh-rsa AAA..."), 600)
|
||||||
|
got, want = f.String(), "echo 'ssh-rsa AAA...' | tee $HOME/.ssh/id_rsa > /dev/null\nchmod 600 $HOME/.ssh/id_rsa\n"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Exepected WriteFile returned \n%s, \ngot\n%s", want, got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,11 @@ func NewHostCert(uri string, cert, key []byte) (*Client, error) {
|
||||||
// if no certificate is provided returns the
|
// if no certificate is provided returns the
|
||||||
// client with no TLS configured.
|
// client with no TLS configured.
|
||||||
if cert == nil || key == nil || len(cert) == 0 || len(key) == 0 {
|
if cert == nil || key == nil || len(cert) == 0 || len(key) == 0 {
|
||||||
|
cli.trans = &http.Transport{
|
||||||
|
Dial: func(dial_network, dial_addr string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout(cli.proto, cli.addr, 32*time.Second)
|
||||||
|
},
|
||||||
|
}
|
||||||
return cli, nil
|
return cli, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +368,7 @@ func (c *Client) HTTPClient() *http.Client {
|
||||||
return &http.Client{Transport: c.trans}
|
return &http.Client{Transport: c.trans}
|
||||||
}
|
}
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
|
// WARN Leak Transport's Pooling Connection
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
Dial: func(dial_network, dial_addr string) (net.Conn, error) {
|
Dial: func(dial_network, dial_addr string) (net.Conn, error) {
|
||||||
return net.DialTimeout(c.proto, c.addr, 32*time.Second)
|
return net.DialTimeout(c.proto, c.addr, 32*time.Second)
|
||||||
|
@ -377,3 +383,9 @@ func (c *Client) Dial() (net.Conn, error) {
|
||||||
}
|
}
|
||||||
return net.Dial(c.proto, c.addr)
|
return net.Dial(c.proto, c.addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) CloseIdleConnections() {
|
||||||
|
if c.trans != nil {
|
||||||
|
c.trans.CloseIdleConnections()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ type Docker struct {
|
||||||
// NetworkMode (also known as `--net` option)
|
// NetworkMode (also known as `--net` option)
|
||||||
// Could be set only if Docker is running in privileged mode
|
// Could be set only if Docker is running in privileged mode
|
||||||
NetworkMode *string `yaml:"net,omitempty"`
|
NetworkMode *string `yaml:"net,omitempty"`
|
||||||
|
|
||||||
|
// Hostname (also known as `--hostname` option)
|
||||||
|
// Could be set only if Docker is running in privileged mode
|
||||||
|
Hostname *string `yaml:"hostname,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DockerNetworkMode returns DefaultNetworkMode
|
// DockerNetworkMode returns DefaultNetworkMode
|
||||||
|
@ -22,3 +26,14 @@ func DockerNetworkMode(d *Docker) string {
|
||||||
}
|
}
|
||||||
return *d.NetworkMode
|
return *d.NetworkMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DockerNetworkMode returns empty string
|
||||||
|
// when Docker.NetworkMode is empty.
|
||||||
|
// DockerNetworkMode returns Docker.NetworkMode
|
||||||
|
// when it is not empty.
|
||||||
|
func DockerHostname(d *Docker) string {
|
||||||
|
if d == nil || d.Hostname == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *d.Hostname
|
||||||
|
}
|
||||||
|
|
|
@ -38,3 +38,32 @@ func TestDockerNetworkMode(t *testing.T) {
|
||||||
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDockerHostname(t *testing.T) {
|
||||||
|
var d *Docker
|
||||||
|
var expected string
|
||||||
|
|
||||||
|
expected = ""
|
||||||
|
d = nil
|
||||||
|
if actual := DockerHostname(d); actual != expected {
|
||||||
|
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = ""
|
||||||
|
d = &Docker{}
|
||||||
|
if actual := DockerHostname(d); actual != expected {
|
||||||
|
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = ""
|
||||||
|
d = &Docker{Hostname: nil}
|
||||||
|
if actual := DockerHostname(d); actual != expected {
|
||||||
|
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = "host"
|
||||||
|
d = &Docker{Hostname: &expected}
|
||||||
|
if actual := DockerHostname(d); actual != expected {
|
||||||
|
t.Errorf("The result is invalid. [expected: %s][actual: %s]", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ func ParseBuild(data string) (*Build, error) {
|
||||||
return &build, err
|
return &build, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseBuildFile(filename string) (*Build, error) {
|
func ParseBuildFile(filename string, params map[string]string) (*Build, error) {
|
||||||
data, err := ioutil.ReadFile(filename)
|
data, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseBuild(string(data))
|
return ParseBuild(Inject(string(data), params))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build stores the configuration details for
|
// Build stores the configuration details for
|
||||||
|
|
|
@ -6,6 +6,7 @@ const (
|
||||||
RemoteGithubEnterprise = "enterprise.github.com"
|
RemoteGithubEnterprise = "enterprise.github.com"
|
||||||
RemoteBitbucket = "bitbucket.org"
|
RemoteBitbucket = "bitbucket.org"
|
||||||
RemoteStash = "stash.atlassian.com"
|
RemoteStash = "stash.atlassian.com"
|
||||||
|
RemoteGogs = "gogs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Remote struct {
|
type Remote struct {
|
||||||
|
|
Loading…
Reference in a new issue