From fdfceedb7d6ffd9ed51ee8c22bbaedaf185cb72c Mon Sep 17 00:00:00 2001 From: Nils Werner Date: Sun, 16 Nov 2014 14:34:54 +0100 Subject: [PATCH 01/23] Removed commit List User limit --- server/datastore/database/commit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/datastore/database/commit.go b/server/datastore/database/commit.go index 3ad6e2c37..ac743e69a 100644 --- a/server/datastore/database/commit.go +++ b/server/datastore/database/commit.go @@ -122,7 +122,7 @@ WHERE c.repo_id = r.repo_id AND r.repo_id = p.repo_id AND p.user_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 @@ -144,7 +144,7 @@ LIMIT 20 const commitListQuery = ` SELECT * FROM commits -WHERE repo_id = ? +WHERE repo_id = ? ORDER BY commit_id DESC LIMIT 20 ` From 7c27628976167968203e850da252433ae6fba7ea Mon Sep 17 00:00:00 2001 From: Mark Steve Samson Date: Thu, 23 Oct 2014 14:00:29 +0800 Subject: [PATCH 02/23] Update Slack plugin config (Closes #612) --- plugin/notify/slack.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/plugin/notify/slack.go b/plugin/notify/slack.go index 356948ce4..395a4df63 100644 --- a/plugin/notify/slack.go +++ b/plugin/notify/slack.go @@ -8,7 +8,6 @@ import ( ) const ( - slackEndpoint = "https://%s.slack.com/services/hooks/incoming-webhook?token=%s" slackStartedMessage = "*Building* <%s|%s> (%s) by %s" slackStartedFallbackMessage = "Building %s (%s) by %s" slackSuccessMessage = "*Success* <%s|%s> (%s) by %s" @@ -18,13 +17,12 @@ const ( ) 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"` + WebhookUrl string `yaml:"webhook_url,omitempty"` + Channel string `yaml:"channel,omitempty"` + Username string `yaml:"username,omitempty"` + Started bool `yaml:"on_started,omitempty"` + Success bool `yaml:"on_success,omitempty"` + Failure bool `yaml:"on_failure,omitempty"` } 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 } - // send payload - url := fmt.Sprintf(slackEndpoint, s.Team, s.Token) - - go sendJson(url, payload, nil) + go sendJson(s.WebhookUrl, payload, nil) return nil } From 270ce52b7648d2852de91c5f3dd879d33a37cc20 Mon Sep 17 00:00:00 2001 From: Christopher Brickley Date: Sat, 27 Sep 2014 23:36:11 -0400 Subject: [PATCH 03/23] add gogs support --- plugin/remote/gogs/gogs.go | 183 +++++++++++++++++++++++++ plugin/remote/gogs/register.go | 23 ++++ server/app/scripts/app.js | 8 +- server/app/scripts/controllers/conf.js | 3 + server/app/scripts/filters/filters.js | 4 +- server/app/views/commit_detail.html | 13 +- server/app/views/config.html | 4 +- server/app/views/login.html | 9 +- server/app/views/login_gogs.html | 23 ++++ server/app/views/users_add.html | 3 +- server/main.go | 2 + shared/model/remote.go | 1 + 12 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 plugin/remote/gogs/gogs.go create mode 100644 plugin/remote/gogs/register.go create mode 100644 server/app/views/login_gogs.html diff --git a/plugin/remote/gogs/gogs.go b/plugin/remote/gogs/gogs.go new file mode 100644 index 000000000..9ad32a209 --- /dev/null +++ b/plugin/remote/gogs/gogs.go @@ -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 +} diff --git a/plugin/remote/gogs/register.go b/plugin/remote/gogs/register.go new file mode 100644 index 000000000..592d729f3 --- /dev/null +++ b/plugin/remote/gogs/register.go @@ -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), + ) +} diff --git a/server/app/scripts/app.js b/server/app/scripts/app.js index be352eaff..4f1a670b0 100644 --- a/server/app/scripts/app.js +++ b/server/app/scripts/app.js @@ -52,6 +52,10 @@ app.config(['$routeProvider', '$locationProvider', '$httpProvider', function($ro templateUrl: '/static/views/login_gitlab.html', title: 'GitLab Login', }) + .when('/gogs', { + templateUrl: '/static/views/login_gogs.html', + title: 'Gogs Setup', + }) .when('/setup', { templateUrl: '/static/views/setup.html', controller: 'SetupController', @@ -234,6 +238,6 @@ app.controller("AccountReposController", function($scope, $http, $location, user return true; }; $scope.byRemote = function(entry){ - return $scope.remote == "" || $scope.remote == entry.remote; - }; + return $scope.remote == "" || $scope.remote == entry.remote; + }; }); diff --git a/server/app/scripts/controllers/conf.js b/server/app/scripts/controllers/conf.js index 6e42b7f89..4cc8202f6 100644 --- a/server/app/scripts/controllers/conf.js +++ b/server/app/scripts/controllers/conf.js @@ -30,6 +30,9 @@ angular.module('app').controller("ConfigController", function($scope, $http, rem case 'stash.atlassian.com': $scope.stash = remote; break; + case 'gogs': + $scope.gogs = remote; + break; } } }) diff --git a/server/app/scripts/filters/filters.js b/server/app/scripts/filters/filters.js index bdb4ec0bf..32c1c0886 100644 --- a/server/app/scripts/filters/filters.js +++ b/server/app/scripts/filters/filters.js @@ -144,6 +144,7 @@ case 'enterprise.github.com' : return 'GitHub Enterprise'; case 'bitbucket.org' : return 'Bitbucket'; case 'stash.atlassian.com' : return 'Atlassian Stash'; + case 'gogs' : return 'Gogs'; } } } @@ -160,6 +161,7 @@ case 'enterprise.github.com' : return 'fa-github-square'; case 'bitbucket.org' : 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('unique', unique); -})(); \ No newline at end of file +})(); diff --git a/server/app/views/commit_detail.html b/server/app/views/commit_detail.html index 639b73284..c53f9dfb3 100644 --- a/server/app/views/commit_detail.html +++ b/server/app/views/commit_detail.html @@ -16,8 +16,17 @@ + +
+ + commit + {{ commit.sha | shortHash}} + to {{ commit.branch }} branch + +
+ -
+
commit {{ commit.sha | shortHash}} to {{ commit.branch }} branch
- \ No newline at end of file + diff --git a/server/app/views/config.html b/server/app/views/config.html index 6e6d285c5..8784f5978 100644 --- a/server/app/views/config.html +++ b/server/app/views/config.html @@ -16,14 +16,14 @@ -
+
-
+
diff --git a/server/app/views/login.html b/server/app/views/login.html index 7f08f2714..4de2fd9dc 100644 --- a/server/app/views/login.html +++ b/server/app/views/login.html @@ -1,4 +1,4 @@ - + +
+
+
+ +
+
+ +
+
+ +
+
+
diff --git a/server/app/views/users_add.html b/server/app/views/users_add.html index 07243532f..8b1fc4f4f 100644 --- a/server/app/views/users_add.html +++ b/server/app/views/users_add.html @@ -25,6 +25,7 @@ + @@ -35,4 +36,4 @@
- \ No newline at end of file + diff --git a/server/main.go b/server/main.go index 66f439703..a260ba0f8 100644 --- a/server/main.go +++ b/server/main.go @@ -24,6 +24,7 @@ import ( "github.com/drone/drone/plugin/remote/bitbucket" "github.com/drone/drone/plugin/remote/github" "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/capability" "github.com/drone/drone/server/datastore" @@ -97,6 +98,7 @@ func main() { bitbucket.Register() github.Register() gitlab.Register() + gogs.Register() caps = map[string]bool{} caps[capability.Registration] = *open diff --git a/shared/model/remote.go b/shared/model/remote.go index 74f6ca2c5..ddb2feb15 100644 --- a/shared/model/remote.go +++ b/shared/model/remote.go @@ -6,6 +6,7 @@ const ( RemoteGithubEnterprise = "enterprise.github.com" RemoteBitbucket = "bitbucket.org" RemoteStash = "stash.atlassian.com" + RemoteGogs = "gogs" ) type Remote struct { From 78b8b7dd750cb09344f62e180e4721152af06d04 Mon Sep 17 00:00:00 2001 From: Vsevolod Strukchinsky Date: Thu, 20 Nov 2014 15:18:12 +0500 Subject: [PATCH 04/23] Add hostname in docker section of .drone.yml --- shared/build/build.go | 1 + shared/build/script/docker.go | 15 +++++++++++++++ shared/build/script/docker_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/shared/build/build.go b/shared/build/build.go index be94904b5..b6cde2f64 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -319,6 +319,7 @@ func (b *Builder) teardown() error { func (b *Builder) run() error { // create and run the container conf := docker.Config{ + Hostname: script.DockerHostname(b.Build.Docker), Image: b.image.ID, AttachStdin: false, AttachStdout: true, diff --git a/shared/build/script/docker.go b/shared/build/script/docker.go index 6686045f1..dfceeeba3 100644 --- a/shared/build/script/docker.go +++ b/shared/build/script/docker.go @@ -10,6 +10,10 @@ type Docker struct { // NetworkMode (also known as `--net` option) // Could be set only if Docker is running in privileged mode 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 @@ -22,3 +26,14 @@ func DockerNetworkMode(d *Docker) string { } 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 +} diff --git a/shared/build/script/docker_test.go b/shared/build/script/docker_test.go index 5b6c1e94e..e089d9ea4 100644 --- a/shared/build/script/docker_test.go +++ b/shared/build/script/docker_test.go @@ -38,3 +38,32 @@ func TestDockerNetworkMode(t *testing.T) { 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) + } +} From d31b41626d0c3bb20a0d18e3b6adec87362fbe6e Mon Sep 17 00:00:00 2001 From: Lowstz Chen Date: Mon, 24 Nov 2014 11:41:12 +0800 Subject: [PATCH 05/23] Update drone.toml Run droned throw this error message: `Unable to parse config: no such flag -session-duration` --- packaging/root/etc/drone/drone.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/root/etc/drone/drone.toml b/packaging/root/etc/drone/drone.toml index a53f2e1f0..1e4b459e4 100644 --- a/packaging/root/etc/drone/drone.toml +++ b/packaging/root/etc/drone/drone.toml @@ -11,7 +11,7 @@ port=":80" # [session] # secret="" -# duration="" +# expires="" ##################################################################### # Database configuration, by default using SQLite3. @@ -70,4 +70,4 @@ datasource="/var/lib/drone/drone.sqlite" # nodes=[ # "unix:///var/run/docker.sock", # "unix:///var/run/docker.sock" -# ] \ No newline at end of file +# ] From fdd4547b1c952018d9962023118e16393d2afe54 Mon Sep 17 00:00:00 2001 From: Pierre Kircher Date: Thu, 27 Nov 2014 17:46:15 +0000 Subject: [PATCH 06/23] plugin skeleton for deis fixed test cases --- plugin/deploy/deis/deis.go | 56 +++++++++++++++++++++++++++ plugin/deploy/deis/deis_test.go | 68 +++++++++++++++++++++++++++++++++ plugin/deploy/deployment.go | 5 +++ 3 files changed, 129 insertions(+) create mode 100644 plugin/deploy/deis/deis.go create mode 100644 plugin/deploy/deis/deis_test.go diff --git a/plugin/deploy/deis/deis.go b/plugin/deploy/deis/deis.go new file mode 100644 index 000000000..acc5a7439 --- /dev/null +++ b/plugin/deploy/deis/deis.go @@ -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 +} diff --git a/plugin/deploy/deis/deis_test.go b/plugin/deploy/deis/deis_test.go new file mode 100644 index 000000000..42b053f4d --- /dev/null +++ b/plugin/deploy/deis/deis_test.go @@ -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) + }) + + }) +} diff --git a/plugin/deploy/deployment.go b/plugin/deploy/deployment.go index 6cb5e960c..3e059ac1e 100644 --- a/plugin/deploy/deployment.go +++ b/plugin/deploy/deployment.go @@ -7,6 +7,7 @@ import ( "github.com/drone/drone/plugin/deploy/git" "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/nodejitsu" "github.com/drone/drone/plugin/deploy/tsuru" @@ -19,6 +20,7 @@ type Deploy struct { CloudFoundry *CloudFoundry `yaml:"cloudfoundry,omitempty"` Git *git.Git `yaml:"git,omitempty"` Heroku *heroku.Heroku `yaml:"heroku,omitempty"` + Deis *deis.Deis `yaml:"deis,omitempty"` Modulus *modulus.Modulus `yaml:"modulus,omitempty"` Nodejitsu *nodejitsu.Nodejitsu `yaml:"nodejitsu,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) { 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) { d.Modulus.Write(f) } From 1cb586dfbcc93f9c1366519739d10a0db33e2e19 Mon Sep 17 00:00:00 2001 From: Ke Zhu Date: Sat, 6 Dec 2014 22:52:36 -0500 Subject: [PATCH 07/23] use api key for deployment to heroku --- plugin/deploy/heroku/heroku.go | 8 +++++++- plugin/deploy/heroku/heroku_test.go | 14 +++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/plugin/deploy/heroku/heroku.go b/plugin/deploy/heroku/heroku.go index 60cca50eb..35a80c0ee 100644 --- a/plugin/deploy/heroku/heroku.go +++ b/plugin/deploy/heroku/heroku.go @@ -14,11 +14,16 @@ const ( // 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')" + + // 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 { App string `yaml:"app,omitempty"` Force bool `yaml:"force,omitempty"` + Token string `yaml:"token,omitempty"` Condition *condition.Condition `yaml:"when,omitempty"` } @@ -27,9 +32,10 @@ func (h *Heroku) Write(f *buildfile.Buildfile) { f.WriteCmdSilent(CmdRevParse) f.WriteCmdSilent(CmdGlobalUser) f.WriteCmdSilent(CmdGlobalEmail) + f.WriteCmdSilent(fmt.Sprintf(CmdLogin, h.Token)) // 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 { case true: diff --git a/plugin/deploy/heroku/heroku_test.go b/plugin/deploy/heroku/heroku_test.go index b938f603f..f4a88b831 100644 --- a/plugin/deploy/heroku/heroku_test.go +++ b/plugin/deploy/heroku/heroku_test.go @@ -26,6 +26,18 @@ func Test_Heroku(t *testing.T) { 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() { b := new(buildfile.Buildfile) h := Heroku{ @@ -34,7 +46,7 @@ func Test_Heroku(t *testing.T) { h.Write(b) 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() { From a7df1e59e6f0cbcc10f338482c0817bfd302d974 Mon Sep 17 00:00:00 2001 From: Ke Zhu Date: Sun, 7 Dec 2014 10:45:14 -0500 Subject: [PATCH 08/23] fix --deploy and --publish flags to `drone build` --- cli/build.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/build.go b/cli/build.go index 0c5a3e1b5..cfe8bd21d 100644 --- a/cli/build.go +++ b/cli/build.go @@ -127,10 +127,10 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl } if deploy == false { - s.Publish = nil + s.Deploy = nil } if publish == false { - s.Deploy = nil + s.Publish = nil } // get the repository root directory From c6bc20dca73a1eb2267e032bd44c16365c173f3c Mon Sep 17 00:00:00 2001 From: Ke Zhu Date: Sun, 7 Dec 2014 11:26:43 -0500 Subject: [PATCH 09/23] parse build file with params injection --- cli/build.go | 2 +- shared/build/script/script.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/build.go b/cli/build.go index 0c5a3e1b5..933b25479 100644 --- a/cli/build.go +++ b/cli/build.go @@ -115,7 +115,7 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl envs := getParamMap("DRONE_ENV_") // parse the Drone yml file - s, err := script.ParseBuildFile(script.Inject(path, envs)) + s, err := script.ParseBuildFile(path, envs) if err != nil { log.Err(err.Error()) return EXIT_STATUS, err diff --git a/shared/build/script/script.go b/shared/build/script/script.go index 62fa8e7eb..1ee261610 100644 --- a/shared/build/script/script.go +++ b/shared/build/script/script.go @@ -22,13 +22,13 @@ func ParseBuild(data string) (*Build, error) { return &build, err } -func ParseBuildFile(filename string) (*Build, error) { +func ParseBuildFile(filename string, params map[string]string) (*Build, error) { data, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return ParseBuild(string(data)) + return ParseBuild(Inject(string(data), params)) } // Build stores the configuration details for From d1099bcf53de3f5c9dc22d70798014cd2a21d40a Mon Sep 17 00:00:00 2001 From: Michael Steinert Date: Wed, 26 Nov 2014 16:21:52 -0600 Subject: [PATCH 10/23] Add Gitlab certificate verification configuration Requires Bugagazavr/go-gitlab-client@4e00e401096c8a1fcab40bdc4f7aa03b6da0b57c --- README.md | 4 +++- packaging/root/etc/drone/drone.toml | 1 + plugin/remote/gitlab/gitlab.go | 18 +++++++++++------- plugin/remote/gitlab/gitlab_test.go | 2 +- plugin/remote/gitlab/helper.go | 4 ++-- plugin/remote/gitlab/register.go | 8 ++++++-- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8b90ae4be..307656bdf 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ secret="" [gitlab] url="" +skip_verify=false [smtp] host="" @@ -169,6 +170,7 @@ export DRONE_BITBUCKET_SECRET="" # gitlab configuration export DRONE_GITLAB_URL="" +export DRONE_GITLAB_SKIP_VERIFY=false # email configuration export DRONE_SMTP_HOST="" @@ -216,4 +218,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 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 \ No newline at end of file +https://github.com/drone/drone/blob/v0.2.1/README.md#builds diff --git a/packaging/root/etc/drone/drone.toml b/packaging/root/etc/drone/drone.toml index 1e4b459e4..77f99f0ab 100644 --- a/packaging/root/etc/drone/drone.toml +++ b/packaging/root/etc/drone/drone.toml @@ -51,6 +51,7 @@ datasource="/var/lib/drone/drone.sqlite" # [gitlab] # url="" +# skip_verify=false ##################################################################### diff --git a/plugin/remote/gitlab/gitlab.go b/plugin/remote/gitlab/gitlab.go index b4e07597d..560678ece 100644 --- a/plugin/remote/gitlab/gitlab.go +++ b/plugin/remote/gitlab/gitlab.go @@ -11,11 +11,15 @@ import ( ) type Gitlab struct { - url string + url string + SkipVerify bool } -func New(url string) *Gitlab { - return &Gitlab{url: url} +func New(url string, skipVerify bool) *Gitlab { + return &Gitlab{ + url: url, + SkipVerify: skipVerify, + } } // 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 password = req.FormValue("password") - var client = NewClient(r.url, "") + var client = NewClient(r.url, "", r.SkipVerify) var session, err = client.GetSession(username, password) if err != nil { return nil, err @@ -55,7 +59,7 @@ func (r *Gitlab) GetHost() string { func (r *Gitlab) GetRepos(user *model.User) ([]*model.Repo, error) { 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() if err != nil { 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 // repository and returns in string format. 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) 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 // a Public Deploy key, if applicable. 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 title, err = GetKeyTitle(link) if err != nil { diff --git a/plugin/remote/gitlab/gitlab_test.go b/plugin/remote/gitlab/gitlab_test.go index ca7e2ba0f..38c331364 100644 --- a/plugin/remote/gitlab/gitlab_test.go +++ b/plugin/remote/gitlab/gitlab_test.go @@ -14,7 +14,7 @@ func Test_Github(t *testing.T) { var server = testdata.NewServer() defer server.Close() - var gitlab = New(server.URL) + var gitlab = New(server.URL, false) var user = model.User{ Access: "e3b0c44298fc1c149afbf4c8996fb", } diff --git a/plugin/remote/gitlab/helper.go b/plugin/remote/gitlab/helper.go index ea2fb25f1..c497c3699 100644 --- a/plugin/remote/gitlab/helper.go +++ b/plugin/remote/gitlab/helper.go @@ -9,8 +9,8 @@ import ( // NewClient is a helper function that returns a new GitHub // client using the provided OAuth token. -func NewClient(uri, token string) *gogitlab.Gitlab { - return gogitlab.NewGitlab(uri, "/api/v3", token) +func NewClient(uri, token string, skipVerify bool) *gogitlab.Gitlab { + return gogitlab.NewGitlabCert(uri, "/api/v3", token, skipVerify) } // IsRead is a helper function that returns true if the diff --git a/plugin/remote/gitlab/register.go b/plugin/remote/gitlab/register.go index eaac24670..c4e7e4c48 100644 --- a/plugin/remote/gitlab/register.go +++ b/plugin/remote/gitlab/register.go @@ -6,7 +6,8 @@ import ( ) 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 @@ -17,6 +18,9 @@ func Register() { return } remote.Register( - New(*gitlabURL), + New( + *gitlabURL, + *gitlabSkipVerify, + ), ) } From 12baa7a81a11dabc5914972ef4886f96484ee0b3 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Wed, 10 Dec 2014 17:57:39 +0300 Subject: [PATCH 11/23] Fix docker TLS, update readme and config file --- README.md | 4 +++- packaging/root/etc/drone/drone.toml | 4 +++- server/main.go | 19 +++++++++++++++---- server/worker/docker/docker.go | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8b90ae4be..68160bc1a 100644 --- a/README.md +++ b/README.md @@ -122,9 +122,11 @@ from="" user="" pass="" -[worker] +[docker] cert="" key="" + +[worker] nodes=[ "unix:///var/run/docker.sock", "unix:///var/run/docker.sock" diff --git a/packaging/root/etc/drone/drone.toml b/packaging/root/etc/drone/drone.toml index 1e4b459e4..4d07b129f 100644 --- a/packaging/root/etc/drone/drone.toml +++ b/packaging/root/etc/drone/drone.toml @@ -64,9 +64,11 @@ datasource="/var/lib/drone/drone.sqlite" # user="" # pass="" -# [worker] +# [docker] # cert="" # key="" + +# [worker] # nodes=[ # "unix:///var/run/docker.sock", # "unix:///var/run/docker.sock" diff --git a/server/main.go b/server/main.go index a260ba0f8..ee618016d 100644 --- a/server/main.go +++ b/server/main.go @@ -34,6 +34,10 @@ import ( "github.com/drone/drone/server/worker/pool" ) +const ( + DockerTLSWarning = `WARINING: Docker TLS cert or key not given, this may cause a build errors` +) + var ( // commit sha for the current build, set by // the compile process. @@ -61,9 +65,9 @@ var ( pub *pubsub.PubSub // Docker configuration details. - dockercrt = config.String("docker-cert", "") - dockerkey = config.String("docker-key", "") - nodes StringArr + dockercert = config.String("docker-cert", "") + dockerkey = config.String("docker-key", "") + nodes StringArr db *sql.DB @@ -117,7 +121,14 @@ func main() { workers.Allocate(docker.New()) } else { 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)) + } } } diff --git a/server/worker/docker/docker.go b/server/worker/docker/docker.go index d00f77521..bff55e2a6 100644 --- a/server/worker/docker/docker.go +++ b/server/worker/docker/docker.go @@ -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) { // ensure that we can recover from any panics to From 82f6b77bafba41a909385d4bad06b3ab9e0764ec Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Wed, 10 Dec 2014 20:06:17 +0300 Subject: [PATCH 12/23] Move id_rsa outside docker build #PR1 --- shared/build/build.go | 20 ++------------------ shared/build/build_test.go | 22 ++-------------------- shared/build/buildfile/buildfile.go | 13 +++++++++++++ shared/build/buildfile/buildfile_test.go | 7 +++++++ 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/shared/build/build.go b/shared/build/build.go index be94904b5..1af2f01bd 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -218,10 +218,6 @@ func (b *Builder) setup() error { b.services = append(b.services, info) } - if err := b.writeIdentifyFile(dir); err != nil { - return err - } - if err := b.writeBuildScript(dir); err != nil { return err } @@ -455,11 +451,8 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("LOGNAME", "ubuntu") dockerfile.WriteEnv("TERM", "xterm") 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 /usr/local/bin/drone") - dockerfile.WriteRun("sudo chmod 600 /home/ubuntu/.ssh/id_rsa") default: // all other images are assumed to use // the root user. @@ -471,9 +464,6 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("TERM", "xterm") 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/") @@ -512,6 +502,8 @@ func (b *Builder) writeBuildScript(dir string) error { f.WriteHost(mapping) } + f.WriteFile("$HOME/.ssh/id_rsa", b.Key, 600) + // if the repository is remote then we should // add the commands to the build script to // clone the repository @@ -554,11 +546,3 @@ func (b *Builder) writeProxyScript(dir string) error { proxyfilePath := filepath.Join(dir, "proxy.sh") 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) -} diff --git a/shared/build/build_test.go b/shared/build/build_test.go index bf05a3550..25eee4a15 100644 --- a/shared/build/build_test.go +++ b/shared/build/build_test.go @@ -477,26 +477,6 @@ func TestRunErrorWait(t *testing.T) { 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) { // temporary directory to store file dir, _ := ioutil.TempDir("", "drone-test-") @@ -541,6 +521,7 @@ func TestWriteBuildScript(t *testing.T) { b := Builder{} b.Build = &script.Build{ Hosts: []string{"127.0.0.1"}} + b.Key = []byte("ssh-rsa AAA...") b.Repo = &repo.Repo{ Path: "git://github.com/drone/drone.git", Branch: "master", @@ -570,6 +551,7 @@ func TestWriteBuildScript(t *testing.T) { f.WriteEnv("CI_BRANCH", "master") f.WriteEnv("CI_PULL_REQUEST", "123") 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 fetch origin +refs/pull/123/head:refs/remotes/origin/pr/123") f.WriteCmd("git checkout -qf -b pr/123 origin/pr/123") diff --git a/shared/build/buildfile/buildfile.go b/shared/build/buildfile/buildfile.go index c08463808..519356216 100644 --- a/shared/build/buildfile/buildfile.go +++ b/shared/build/buildfile/buildfile.go @@ -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)) } +// WriteFile add files as part of the script. +func (b *Buildfile) WriteFile(path string, file []byte, i int) { + b.WriteString(fmt.Sprintf("echo %q | tee %s > /dev/null\n", string(file), path)) + b.WriteCmdSilent(fmt.Sprintf("chmod %d %s", i, path)) +} + // every build script starts with the following // code at the start. var base = ` @@ -70,6 +76,13 @@ if [ -d /etc/drone.d ]; then unset i 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 # our bash commands, so we can which commands # are executing and troubleshoot failures. diff --git a/shared/build/buildfile/buildfile_test.go b/shared/build/buildfile/buildfile_test.go index f9e0e942f..a9fa2dd50 100644 --- a/shared/build/buildfile/buildfile_test.go +++ b/shared/build/buildfile/buildfile_test.go @@ -46,4 +46,11 @@ func TestWrite(t *testing.T) { if got != want { 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) + } } From 9dec0d4a26515bc628322f92591347447e5dfacf Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Thu, 11 Dec 2014 14:30:15 -0800 Subject: [PATCH 13/23] Revert "Move id_rsa outside docker build #PR1" --- shared/build/build.go | 20 ++++++++++++++++++-- shared/build/build_test.go | 22 ++++++++++++++++++++-- shared/build/buildfile/buildfile.go | 13 ------------- shared/build/buildfile/buildfile_test.go | 7 ------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/shared/build/build.go b/shared/build/build.go index 1af2f01bd..be94904b5 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -218,6 +218,10 @@ func (b *Builder) setup() error { b.services = append(b.services, info) } + if err := b.writeIdentifyFile(dir); err != nil { + return err + } + if err := b.writeBuildScript(dir); err != nil { return err } @@ -451,8 +455,11 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("LOGNAME", "ubuntu") dockerfile.WriteEnv("TERM", "xterm") 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 /usr/local/bin/drone") + dockerfile.WriteRun("sudo chmod 600 /home/ubuntu/.ssh/id_rsa") default: // all other images are assumed to use // the root user. @@ -464,6 +471,9 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("TERM", "xterm") 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/") @@ -502,8 +512,6 @@ func (b *Builder) writeBuildScript(dir string) error { f.WriteHost(mapping) } - f.WriteFile("$HOME/.ssh/id_rsa", b.Key, 600) - // if the repository is remote then we should // add the commands to the build script to // clone the repository @@ -546,3 +554,11 @@ func (b *Builder) writeProxyScript(dir string) error { proxyfilePath := filepath.Join(dir, "proxy.sh") 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) +} diff --git a/shared/build/build_test.go b/shared/build/build_test.go index 25eee4a15..bf05a3550 100644 --- a/shared/build/build_test.go +++ b/shared/build/build_test.go @@ -477,6 +477,26 @@ func TestRunErrorWait(t *testing.T) { 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) { // temporary directory to store file dir, _ := ioutil.TempDir("", "drone-test-") @@ -521,7 +541,6 @@ func TestWriteBuildScript(t *testing.T) { b := Builder{} b.Build = &script.Build{ Hosts: []string{"127.0.0.1"}} - b.Key = []byte("ssh-rsa AAA...") b.Repo = &repo.Repo{ Path: "git://github.com/drone/drone.git", Branch: "master", @@ -551,7 +570,6 @@ func TestWriteBuildScript(t *testing.T) { f.WriteEnv("CI_BRANCH", "master") f.WriteEnv("CI_PULL_REQUEST", "123") 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 fetch origin +refs/pull/123/head:refs/remotes/origin/pr/123") f.WriteCmd("git checkout -qf -b pr/123 origin/pr/123") diff --git a/shared/build/buildfile/buildfile.go b/shared/build/buildfile/buildfile.go index 519356216..c08463808 100644 --- a/shared/build/buildfile/buildfile.go +++ b/shared/build/buildfile/buildfile.go @@ -52,12 +52,6 @@ func (b *Buildfile) WriteHost(mapping string) { 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 %q | tee %s > /dev/null\n", string(file), path)) - b.WriteCmdSilent(fmt.Sprintf("chmod %d %s", i, path)) -} - // every build script starts with the following // code at the start. var base = ` @@ -76,13 +70,6 @@ if [ -d /etc/drone.d ]; then unset i 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 # our bash commands, so we can which commands # are executing and troubleshoot failures. diff --git a/shared/build/buildfile/buildfile_test.go b/shared/build/buildfile/buildfile_test.go index a9fa2dd50..f9e0e942f 100644 --- a/shared/build/buildfile/buildfile_test.go +++ b/shared/build/buildfile/buildfile_test.go @@ -46,11 +46,4 @@ func TestWrite(t *testing.T) { if got != want { 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) - } } From 6b586c62daaaa24074aed26f2feb8b4b63e41e59 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Wed, 10 Dec 2014 20:06:17 +0300 Subject: [PATCH 14/23] Move id_rsa outside docker build #PR1 --- shared/build/build.go | 20 ++------------------ shared/build/build_test.go | 22 ++-------------------- shared/build/buildfile/buildfile.go | 13 +++++++++++++ shared/build/buildfile/buildfile_test.go | 7 +++++++ 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/shared/build/build.go b/shared/build/build.go index be94904b5..1af2f01bd 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -218,10 +218,6 @@ func (b *Builder) setup() error { b.services = append(b.services, info) } - if err := b.writeIdentifyFile(dir); err != nil { - return err - } - if err := b.writeBuildScript(dir); err != nil { return err } @@ -455,11 +451,8 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("LOGNAME", "ubuntu") dockerfile.WriteEnv("TERM", "xterm") 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 /usr/local/bin/drone") - dockerfile.WriteRun("sudo chmod 600 /home/ubuntu/.ssh/id_rsa") default: // all other images are assumed to use // the root user. @@ -471,9 +464,6 @@ func (b *Builder) writeDockerfile(dir string) error { dockerfile.WriteEnv("TERM", "xterm") 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/") @@ -512,6 +502,8 @@ func (b *Builder) writeBuildScript(dir string) error { f.WriteHost(mapping) } + f.WriteFile("$HOME/.ssh/id_rsa", b.Key, 600) + // if the repository is remote then we should // add the commands to the build script to // clone the repository @@ -554,11 +546,3 @@ func (b *Builder) writeProxyScript(dir string) error { proxyfilePath := filepath.Join(dir, "proxy.sh") 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) -} diff --git a/shared/build/build_test.go b/shared/build/build_test.go index bf05a3550..25eee4a15 100644 --- a/shared/build/build_test.go +++ b/shared/build/build_test.go @@ -477,26 +477,6 @@ func TestRunErrorWait(t *testing.T) { 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) { // temporary directory to store file dir, _ := ioutil.TempDir("", "drone-test-") @@ -541,6 +521,7 @@ func TestWriteBuildScript(t *testing.T) { b := Builder{} b.Build = &script.Build{ Hosts: []string{"127.0.0.1"}} + b.Key = []byte("ssh-rsa AAA...") b.Repo = &repo.Repo{ Path: "git://github.com/drone/drone.git", Branch: "master", @@ -570,6 +551,7 @@ func TestWriteBuildScript(t *testing.T) { f.WriteEnv("CI_BRANCH", "master") f.WriteEnv("CI_PULL_REQUEST", "123") 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 fetch origin +refs/pull/123/head:refs/remotes/origin/pr/123") f.WriteCmd("git checkout -qf -b pr/123 origin/pr/123") diff --git a/shared/build/buildfile/buildfile.go b/shared/build/buildfile/buildfile.go index c08463808..723ca1af1 100644 --- a/shared/build/buildfile/buildfile.go +++ b/shared/build/buildfile/buildfile.go @@ -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)) } +// 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 // code at the start. var base = ` @@ -70,6 +76,13 @@ if [ -d /etc/drone.d ]; then unset i 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 # our bash commands, so we can which commands # are executing and troubleshoot failures. diff --git a/shared/build/buildfile/buildfile_test.go b/shared/build/buildfile/buildfile_test.go index f9e0e942f..080a84f6f 100644 --- a/shared/build/buildfile/buildfile_test.go +++ b/shared/build/buildfile/buildfile_test.go @@ -46,4 +46,11 @@ func TestWrite(t *testing.T) { if got != want { 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) + } } From 6609d09e91898223c5a60984603adf2d3351aade Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Fri, 12 Dec 2014 12:01:12 +0300 Subject: [PATCH 15/23] Move env variables outsude docker build #PR2 --- shared/build/build.go | 20 +++++++++----------- shared/build/build_test.go | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/shared/build/build.go b/shared/build/build.go index 1af2f01bd..03aa42a4d 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -445,25 +445,16 @@ func (b *Builder) writeDockerfile(dir string) error { // is the "ubuntu" user, since all build images // inherit from the ubuntu cloud ISO 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("TERM", "xterm") - dockerfile.WriteEnv("SHELL", "/bin/bash") + dockerfile.WriteEnv("HOME", "/home/ubuntu") dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /var/cache/drone") dockerfile.WriteRun("sudo chown -R ubuntu:ubuntu /usr/local/bin/drone") default: // all other images are assumed to use // the root user. 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("TERM", "xterm") - dockerfile.WriteEnv("SHELL", "/bin/bash") - dockerfile.WriteEnv("GOPATH", "/var/cache/drone") + dockerfile.WriteEnv("HOME", "/root") } dockerfile.WriteAdd("proxy.sh", "/etc/drone.d/") @@ -479,6 +470,13 @@ func (b *Builder) writeDockerfile(dir string) error { func (b *Builder) writeBuildScript(dir string) error { 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 f.WriteEnv("CI", "true") f.WriteEnv("DRONE", "true") diff --git a/shared/build/build_test.go b/shared/build/build_test.go index 25eee4a15..e1eaea07e 100644 --- a/shared/build/build_test.go +++ b/shared/build/build_test.go @@ -537,6 +537,11 @@ func TestWriteBuildScript(t *testing.T) { } 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("DRONE", "true") f.WriteEnv("DRONE_REMOTE", "git://github.com/drone/drone.git") From 3d244fcdae3d6fb77e38a080c5829c0df86d5202 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Fri, 12 Dec 2014 14:30:52 +0300 Subject: [PATCH 16/23] Added KatoIM support --- plugin/notify/katoim/katoim.go | 139 +++++++++++++++++++++++++++++++++ plugin/notify/notification.go | 10 +++ 2 files changed, 149 insertions(+) create mode 100644 plugin/notify/katoim/katoim.go diff --git a/plugin/notify/katoim/katoim.go b/plugin/notify/katoim/katoim.go new file mode 100644 index 000000000..29dd14e25 --- /dev/null +++ b/plugin/notify/katoim/katoim.go @@ -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 +} diff --git a/plugin/notify/notification.go b/plugin/notify/notification.go index 982be477b..c836752f7 100644 --- a/plugin/notify/notification.go +++ b/plugin/notify/notification.go @@ -9,6 +9,7 @@ import ( "github.com/drone/drone/plugin/notify/email" "github.com/drone/drone/plugin/notify/github" "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/shared/model" ) @@ -28,6 +29,7 @@ type Notification struct { Slack *Slack `yaml:"slack,omitempty"` Gitter *Gitter `yaml:"gitter,omitempty"` Flowdock *Flowdock `yaml:"flowdock,omitempty"` + KatoIM *katoim.KatoIM `yaml:"katoim,omitempty"` 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 // TODO (bradrydzewski) need to improve this code githubStatus := new(github.GitHub) From 1236d44bfc9eaac99e078577214b8c40bb3b221e Mon Sep 17 00:00:00 2001 From: Amanda Cameron Date: Sat, 13 Dec 2014 09:48:56 -0500 Subject: [PATCH 17/23] Fix the IRC notification plugin. --- plugin/notify/irc/irc.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/plugin/notify/irc/irc.go b/plugin/notify/irc/irc.go index 7e232677f..3d935e102 100644 --- a/plugin/notify/irc/irc.go +++ b/plugin/notify/irc/irc.go @@ -53,11 +53,23 @@ func (i *IRC) sendSuccess(req *model.Request) error { // to the connected IRC client func (i *IRC) send(channel string, message string) error { client := irc.IRC(i.Nick, i.Nick) - if client != nil { + + if client == nil { return fmt.Errorf("Error creating IRC client") } - defer client.Disconnect() - client.Connect(i.Server) - client.Notice(channel, message) + + err := client.Connect(i.Server) + + if err != nil { + return fmt.Errorf("Error connecting to IRC server: %v", err) + } + + client.AddCallback("001", func(_ *irc.Event) { + client.Notice(channel, message) + client.Disconnect() + }) + + go client.Loop() + return nil } From 74f574f864ea9d71a04a11ebcc61a537247db82a Mon Sep 17 00:00:00 2001 From: Amanda Cameron Date: Sat, 13 Dec 2014 10:23:44 -0500 Subject: [PATCH 18/23] Fix IRC notification to use .Quit() instead of .Disconnect() --- plugin/notify/irc/irc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/notify/irc/irc.go b/plugin/notify/irc/irc.go index 3d935e102..33fa02662 100644 --- a/plugin/notify/irc/irc.go +++ b/plugin/notify/irc/irc.go @@ -66,7 +66,7 @@ func (i *IRC) send(channel string, message string) error { client.AddCallback("001", func(_ *irc.Event) { client.Notice(channel, message) - client.Disconnect() + client.Quit() }) go client.Loop() From d4434c2a27c63bc583d59502b62b88aceaf9bf55 Mon Sep 17 00:00:00 2001 From: Gary Borton Date: Tue, 16 Dec 2014 04:04:27 -0500 Subject: [PATCH 19/23] Make Heroku destination refspec more specific. --- plugin/deploy/heroku/heroku.go | 4 ++-- plugin/deploy/heroku/heroku_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/deploy/heroku/heroku.go b/plugin/deploy/heroku/heroku.go index 35a80c0ee..7a551fbb0 100644 --- a/plugin/deploy/heroku/heroku.go +++ b/plugin/deploy/heroku/heroku.go @@ -44,10 +44,10 @@ func (h *Heroku) Write(f *buildfile.Buildfile) { // 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 HEAD:master --force")) + f.WriteCmd(fmt.Sprintf("git push heroku HEAD:refs/heads/master --force")) case false: // 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")) } } diff --git a/plugin/deploy/heroku/heroku_test.go b/plugin/deploy/heroku/heroku_test.go index f4a88b831..e5a8eeef9 100644 --- a/plugin/deploy/heroku/heroku_test.go +++ b/plugin/deploy/heroku/heroku_test.go @@ -57,7 +57,7 @@ func Test_Heroku(t *testing.T) { d.Write(b) 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() { @@ -71,7 +71,7 @@ func Test_Heroku(t *testing.T) { 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 heroku HEAD:master --force\n")).Equal(true) + g.Assert(strings.Contains(out, "\ngit push heroku HEAD:refs/heads/master --force\n")).Equal(true) }) }) From 2059c6f4e6a222f4c8015d977ddd6359375a2bef Mon Sep 17 00:00:00 2001 From: mopemoepe Date: Fri, 19 Dec 2014 01:58:17 +0900 Subject: [PATCH 20/23] Fix Docker Client FileDescriptor Leak --- shared/build/build.go | 2 ++ shared/build/docker/client.go | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/shared/build/build.go b/shared/build/build.go index d85ff2a18..2226cc4fa 100644 --- a/shared/build/build.go +++ b/shared/build/build.go @@ -270,6 +270,8 @@ func (b *Builder) setup() error { // and the supporting service containers. func (b *Builder) teardown() error { + defer b.dockerClient.CloseIdleConnections() + // stop and destroy the container if b.container != nil { diff --git a/shared/build/docker/client.go b/shared/build/docker/client.go index 8961598a0..678059b90 100644 --- a/shared/build/docker/client.go +++ b/shared/build/docker/client.go @@ -71,6 +71,11 @@ func NewHostCert(uri string, cert, key []byte) (*Client, error) { // if no certificate is provided returns the // client with no TLS configured. 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 } @@ -363,6 +368,7 @@ func (c *Client) HTTPClient() *http.Client { return &http.Client{Transport: c.trans} } return &http.Client{ + // WARN Leak Transport's Pooling Connection Transport: &http.Transport{ Dial: func(dial_network, dial_addr string) (net.Conn, error) { 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) } + +func (c *Client) CloseIdleConnections() { + if c.trans != nil { + c.trans.CloseIdleConnections() + } +} From 441de03fb928cc86d2976eff3977876bceb7ce6d Mon Sep 17 00:00:00 2001 From: Michael Steinert Date: Wed, 24 Dec 2014 12:59:03 -0600 Subject: [PATCH 21/23] Serve `robots.txt` from `/` This change allows `robots.txt` to be served from the root URL, i.e. https://drone.io/robots.txt, which is where [web crawlers will look for it][1]. Previously this file was only served from `/static/robots.txt`. [1]: http://www.robotstxt.org/robotstxt.html --- server/app/robots.txt | 2 +- server/main.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/app/robots.txt b/server/app/robots.txt index 4f9540ba3..7d329b1db 100644 --- a/server/app/robots.txt +++ b/server/app/robots.txt @@ -1 +1 @@ -User-agent: * \ No newline at end of file +User-agent: * diff --git a/server/main.go b/server/main.go index ee618016d..9fd47cd2b 100644 --- a/server/main.go +++ b/server/main.go @@ -137,6 +137,7 @@ func main() { // create handler for static resources assets := rice.MustFindBox("app").HTTPBox() assetserve := http.FileServer(rice.MustFindBox("app").HTTPBox()) + http.Handle("/robots.txt", assetserve) http.Handle("/static/", http.StripPrefix("/static", assetserve)) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write(assets.MustBytes("index.html")) From 78981036636b6e1702291a8bd1b8a42dbefc410e Mon Sep 17 00:00:00 2001 From: mopemoepe Date: Mon, 22 Dec 2014 02:06:12 +0900 Subject: [PATCH 22/23] Add Dropbox plugin --- plugin/publish/dropbox.go | 36 ++++++++++++++++++++++++++++++++++++ plugin/publish/publish.go | 18 ++++++++++++------ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/plugin/publish/dropbox.go b/plugin/publish/dropbox.go index 30b1a5b2a..77dba0619 100644 --- a/plugin/publish/dropbox.go +++ b/plugin/publish/dropbox.go @@ -1 +1,37 @@ 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 +} diff --git a/plugin/publish/publish.go b/plugin/publish/publish.go index 19ba9e78a..4ce6d4b1f 100644 --- a/plugin/publish/publish.go +++ b/plugin/publish/publish.go @@ -11,12 +11,13 @@ import ( // 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.NPM `yaml:"npm,omitempty"` - Docker *Docker `yaml:"docker,omitempty"` - Github *Github `yaml:"github,omitempty"` + S3 *S3 `yaml:"s3,omitempty"` + Swift *Swift `yaml:"swift,omitempty"` + PyPI *PyPI `yaml:"pypi,omitempty"` + NPM *npm.NPM `yaml:"npm,omitempty"` + Docker *Docker `yaml:"docker,omitempty"` + Github *Github `yaml:"github,omitempty"` + Dropbox *Dropbox `yaml:"dropbox,omitempty"` } 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) { 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 { From 5b07ef5ffe9d27b62a2071b4c9546d053a34c11a Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Sat, 20 Dec 2014 17:26:33 +0300 Subject: [PATCH 23/23] Automatically detect ENV variables --- cli/build.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/cli/build.go b/cli/build.go index 5dd6f77fa..c14fb09f0 100644 --- a/cli/build.go +++ b/cli/build.go @@ -43,17 +43,17 @@ func NewBuildCommand() cli.Command { }, cli.StringFlag{ Name: "docker-host", - Value: "", + Value: getHost(), Usage: "docker daemon address", }, cli.StringFlag{ Name: "docker-cert", - Value: "", + Value: getCert(), Usage: "docker daemon tls certificate", }, cli.StringFlag{ Name: "docker-key", - Value: "", + Value: getKey(), Usage: "docker daemon tls key", }, }, @@ -204,3 +204,23 @@ func run(path, identity, dockerhost, dockercert, dockerkey string, publish, depl 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 "" + } +}