dockistrano 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 031a5bef368643972d84782c3fe8aec9f9a83cdc
4
+ data.tar.gz: d2f202905234e891b5a2ad5c07b453365d9aec1c
5
+ SHA512:
6
+ metadata.gz: d60c0c8983b6c70f78dca0a130f7db92fd0613117b11e3bb2859eb8b00dd9bfa1df6a81d8f9660978fdeeee7748974adffc60c8e45a2fd098b28d4b3f5501c8a
7
+ data.tar.gz: a341da5a23a8f8cadaed99e1d1febf57f69a5922c497b8732a1d4eb21651c7c425446a129245a77197428a9ade403f49b97dc5b7d5b77dad15b03ee346416b84
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dockistrano.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Edwin Vlieg
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Dockistrano
2
+
3
+ Dockistrano uses docker to create a development and testing environment for applications. It is inspired by Capistrano, because booting a container should be as easy as doing a `cap deploy`. The approach has a lot of conventions and as little as configuration as possible.
4
+
5
+ ## Current status
6
+
7
+ Dockistrano is actively used for software development at [MoneyBird](http://www.moneybird.com), but is still very immature. Feel free to play around and provide us feedback. A pull request with tested code is the best way to help us improve the software!
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'dockistrano'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install dockistrano
22
+
23
+ ## Preparing your application
24
+
25
+ To use Dockistrano for your application, two files should be created:
26
+
27
+ ### `Dockerfile`
28
+
29
+ The `Dockerfile` describes the container that is created for the application and should contain all dependencies. Example:
30
+
31
+ ```
32
+ FROM ubuntu
33
+ RUN apt-get update
34
+ RUN apt-get install mydependency
35
+ ADD ./ ./
36
+ EXPOSE 8000
37
+ CMD ["webserver", "start"]
38
+ ```
39
+
40
+ For more information about writing Dockerfiles, see [the documentation on docker.io](http://docs.docker.io/en/latest/use/builder/).
41
+
42
+ ### `config/dockistrano.yml`
43
+
44
+ The configuration file contains information about the registry, dependencies, ports and environment variables.
45
+
46
+ ```
47
+ ---
48
+ registry: my.privateregistry.com:5000
49
+ dependencies:
50
+ postgresql:
51
+ database: "my_databasename"
52
+ redis:
53
+ environment:
54
+ rails_env: development
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ Dockistrano provides a range of commands to create containers and run commands in containers:
60
+
61
+ ### `doc build`
62
+
63
+ Builds the current container by using the `Dockerfile`. The resulting container will be tagged with the registry name, name of the image and tag of the current git branch.
64
+
65
+ When building is successfull, the container will be tested by running the `test_command` provided in the config. When tests are successfull, the container is pushes to the registry.
66
+
67
+ ### `doc start` and `doc start-services`
68
+
69
+ Starts the container by running the default command. Environment variables from dependencies are automatically added to the run command. Optionally the backing services can be started seperatly with `doc start-services`
70
+
71
+ ### `doc stop` and `doc stop-all`
72
+
73
+ Stops the current container or stops all containers, including the backing services.
74
+
75
+ ### `doc logs [NAME]`
76
+
77
+ Prints logs for the container or for a backing service when a name of the service is provided. When the container is running a `docker attach` is used, otherwise a `docker logs`.
78
+
79
+ ### `doc exec COMMAND`
80
+
81
+ Executes the command in the container, printing the result in the console.
82
+
83
+ ### `doc console [CONSOLE]`
84
+
85
+ Starts a console in the container, by default /bin/bash is started. Optionally a console can be provided, for example `doc console rails console` to start a Rails console.
86
+
87
+ ### `doc ps`
88
+
89
+ Prints all running processes on Docker
90
+
91
+ ### `doc clean`
92
+
93
+ Cleans unused containers and images from Docker
94
+
95
+ ### `doc status`
96
+
97
+ Prints information about the current container and lists environment variables that are provided to the container when started.
98
+
99
+ ### `doc pull`
100
+
101
+ Pulls new versions of containers from the registry
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/doc ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path("../../lib/", __FILE__)
4
+
5
+ require "bundler"
6
+ Bundler.setup(:default)
7
+
8
+ require "dockistrano"
9
+ begin
10
+ Dockistrano::Cli.start
11
+ rescue Thor::InvocationError => e
12
+ puts e
13
+ end
data/bin/docker ADDED
Binary file
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dockistrano/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dockistrano"
8
+ spec.version = Dockistrano::VERSION
9
+ spec.authors = ["Edwin Vlieg"]
10
+ spec.email = ["edwin@moneybird.com"]
11
+ spec.summary = %q{Manage Docker containers for a development workflow}
12
+ spec.homepage = "http://github.com/moneybird/dockistrano"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "thor"
21
+ spec.add_dependency "cocaine"
22
+ spec.add_dependency "multi_json"
23
+ spec.add_dependency "redis"
24
+ spec.add_dependency "dotenv"
25
+
26
+ spec.add_development_dependency "bundler"
27
+ spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "guard"
29
+ spec.add_development_dependency "guard-rspec"
30
+ spec.add_development_dependency "terminal-notifier-guard"
31
+ spec.add_development_dependency "webmock"
32
+ end
@@ -0,0 +1,220 @@
1
+ require 'thor'
2
+ require "dotenv"
3
+ Dotenv.load(".dockistrano")
4
+ ENV["DOCKISTRANO_ENVIRONMENT"] ||= "default"
5
+ ENV["DOCKER_HOST_IP"] ||= "127.0.0.1"
6
+ ENV["DOCKER_BINARY"] ||= begin
7
+ if RUBY_PLATFORM =~ /darwin|mac os/
8
+ bin_dir = File.expand_path(File.dirname(__FILE__) + "/../../bin")
9
+ "#{bin_dir}/docker"
10
+ else
11
+ "docker"
12
+ end
13
+ end
14
+
15
+ module Dockistrano
16
+
17
+ class Cli < ::Thor
18
+
19
+ desc "ps", "List all running containers in docker"
20
+ def ps
21
+ puts Docker.ps
22
+ end
23
+
24
+ desc "setup", "Sets up a host for starting the application"
25
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
26
+ def setup
27
+ say "Please execute the following command on the host to setup", :green
28
+ say "\tmkdir -p #{current_service.directories_required_on_host.join(" ")}"
29
+ end
30
+
31
+ desc "status", "Status of the application"
32
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
33
+ def status
34
+ say "DOCKISTRANO_ENVIRONMENT: #{options["environment"]}", :green
35
+ say "DOCKER_HOST_IP: #{ENV['DOCKER_HOST_IP']}", :green
36
+ say "DOCKER_BINARY: #{ENV['DOCKER_BINARY']}", :green
37
+ say ""
38
+ say "Current application", :blue
39
+ say " registry: #{current_service.registry}"
40
+ say " image name: #{current_service.image_name}"
41
+ say " tag: #{current_service.tag}"
42
+ say " volumes:"
43
+ current_service.volumes.each do |volume|
44
+ say " #{volume}"
45
+ end
46
+ say ""
47
+ say "Dependencies", :blue
48
+ current_service.backing_services.each do |name, service|
49
+ say " #{service.full_image_name}"
50
+ end
51
+ say ""
52
+ say "Environment", :blue
53
+ current_service.environment_variables.each do |key, value|
54
+ say " #{key}=#{value}"
55
+ end
56
+ say ""
57
+ say "Hipache", :blue
58
+ Hipache.new(ENV["DOCKER_HOST_IP"]).status.each do |host, ips|
59
+ say " #{host}: #{ips.join(", ")}"
60
+ end
61
+ say ""
62
+ end
63
+
64
+ desc "build", "Build and test a new application container"
65
+ def build
66
+ if current_service.build
67
+ say_status "built", current_service.image_name
68
+ if current_service.test
69
+ say_status "tests passed", current_service.image_name
70
+ current_service.push
71
+ say_status "pushed", current_service.image_name
72
+ else
73
+ say_status "tests failed", current_service.image_name
74
+ exit 1
75
+ end
76
+ else
77
+ say_status "failed", current_service.image_name, :red
78
+ exit 1
79
+ end
80
+ end
81
+
82
+ desc "pull", "Pull new versions of dependencies"
83
+ def pull
84
+ current_service.backing_services.each do |name, service|
85
+ if service.newer_version_available?
86
+ service.pull
87
+ say_status "Pulled", name
88
+ else
89
+ say_status "Uptodate", name, :white
90
+ end
91
+ end
92
+
93
+ if current_service.newer_version_available?
94
+ current_service.pull
95
+ say_status "Pulled", current_service.image_name
96
+ else
97
+ say_status "Uptodate", current_service.image_name, :white
98
+ end
99
+ end
100
+
101
+ desc "push", "Pushes a new version of this container"
102
+ def push
103
+ current_service.push
104
+ end
105
+
106
+ desc "start-services", "Starts the backing services"
107
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
108
+ def start_services
109
+ current_service.backing_services.each do |name, service|
110
+ if service.running?
111
+ say_status("Running", name, :white)
112
+ else
113
+ service.start
114
+ say_status("Started", name)
115
+ end
116
+ end
117
+ end
118
+
119
+ desc "stop-all", "Stops the backing services"
120
+ def stop_all
121
+ current_service.stop
122
+ say_status("Stopped", current_service.image_name)
123
+ current_service.backing_services.each do |name, service|
124
+ if service.running?
125
+ service.stop
126
+ say_status("Stopped", name)
127
+ end
128
+ end
129
+ end
130
+
131
+ desc "start", "Starts the application"
132
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
133
+ def start
134
+ if current_service.running?
135
+ say_status("Running", current_service.image_name, :white)
136
+ else
137
+ current_service.start(options)
138
+ say_status("Started", current_service.image_name)
139
+ end
140
+ rescue Dockistrano::Service::EnvironmentVariablesMissing => e
141
+ say e.message, :red
142
+ end
143
+
144
+ desc "stop [ID]", "Stops the application or container with specified ID"
145
+ def stop(id=nil)
146
+ if id
147
+ Docker.stop(id)
148
+ say_status("Stopped", id, :green)
149
+ else
150
+ current_service.stop
151
+ say_status("Stopped", current_service.image_name, :green)
152
+ end
153
+ end
154
+
155
+ desc "restart", "Restarts the application"
156
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
157
+ def restart
158
+ current_service.stop
159
+ say_status("Stopped", current_service.image_name)
160
+ current_service.start(options)
161
+ say_status("Started", current_service.image_name)
162
+ end
163
+
164
+ desc "exec COMMAND", "Executes a command in the application and returns"
165
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
166
+ def exec(*command)
167
+ current_service.exec(command.join(" "), options)
168
+ rescue Dockistrano::Service::EnvironmentVariablesMissing => e
169
+ say e.message, :red
170
+ end
171
+
172
+ desc "console [COMMAND]", "Starts an interactive shell in the application"
173
+ method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
174
+ def console(*command)
175
+ command = ["/bin/bash"] if command.empty?
176
+ current_service.console(command.join(" "), options)
177
+ rescue Dockistrano::Service::EnvironmentVariablesMissing => e
178
+ say e.message, :red
179
+ end
180
+
181
+ desc "clean", "Cleans images and containers from docker"
182
+ def clean
183
+ Docker.clean
184
+ Dockistrano::ServiceDependency.clear_cache
185
+ end
186
+
187
+ desc "logs [NAME]", "Prints the logs for the service"
188
+ def logs(name=nil)
189
+ service = name ? current_service.backing_services[name] : current_service
190
+ if service.running?
191
+ say "Container #{service.image_name} running, attaching to output", :blue
192
+ service.attach
193
+ else
194
+ say "Container #{service.image_name} stopped, printing logs of last run", :blue
195
+ service.logs
196
+ end
197
+ end
198
+
199
+ def method_missing(*args)
200
+ command = args[0]
201
+ if command and current_service.config["aliases"] and current_service.config["aliases"][command.to_s]
202
+ args.shift
203
+ Kernel.exec("doc #{current_service.config["aliases"][command.to_s]} #{args.join(" ")}")
204
+ else
205
+ super
206
+ end
207
+ end
208
+
209
+ private
210
+
211
+ # Returns the current service
212
+ def current_service
213
+ @service ||= Service.factory(Dir.pwd, options["environment"])
214
+ rescue Dockistrano::Service::ConfigurationFileMissing
215
+ say "No configuration file found in current directory. config/dockistrano.yml missing", :red
216
+ exit 1
217
+ end
218
+
219
+ end
220
+ end
@@ -0,0 +1,28 @@
1
+ module Dockistrano
2
+
3
+ class CommandLine
4
+
5
+ def self.command_with_result(command)
6
+ debug(command)
7
+ `#{command}`
8
+ end
9
+
10
+ def self.command_with_stream(command)
11
+ debug(command)
12
+ begin
13
+ Kernel.system(command)
14
+ rescue Interrupt
15
+ end
16
+ end
17
+
18
+ def self.command_with_interaction(command)
19
+ debug(command)
20
+ Kernel.exec(command)
21
+ end
22
+
23
+ def self.debug(command)
24
+ puts "$ #{command}" if false
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,188 @@
1
+ require 'cocaine'
2
+ require 'multi_json'
3
+
4
+ module Dockistrano
5
+
6
+ # Class for communication with Docker. Uses two means of communication:
7
+ #
8
+ # - Actions on containers are executed by calling the docker binary with an
9
+ # ip address of the Docker location. The docker command line client is best
10
+ # capable of executing the actions for building images, running containers and
11
+ # managing containers.
12
+ # - Queries are executed using the HTTP API of docker. This API is exposed via HTTP
13
+ # and returns JSON. This allows us to easily parse and return the information.
14
+ #
15
+ # This class uses two environment variables:
16
+ #
17
+ # DOCKER_BINARY - Location of the docker binary on your system
18
+ # DOCKER_HOST_IP - IP address or host of the docker server
19
+ #
20
+ class Docker
21
+
22
+ class EnvironmentVariableMissing < StandardError
23
+ end
24
+
25
+ # Returns the docker command as a string: 'docker -H 127.0.0.1'
26
+ def self.docker_command
27
+ raise EnvironmentVariableMissing.new("Missing DOCKER_BINARY in environment, please provide the location of the docker binary") unless ENV["DOCKER_BINARY"]
28
+ raise EnvironmentVariableMissing.new("Missing DOCKER_HOST_IP in environment, please provide the host or ip address of the docker server") unless ENV["DOCKER_HOST_IP"]
29
+ "#{ENV['DOCKER_BINARY']} -H #{ENV['DOCKER_HOST_IP']}"
30
+ end
31
+
32
+ # Executes the given command on the command line
33
+ def self.execute(command, mode=:string_result)
34
+ case mode
35
+ when :string_result
36
+ Dockistrano::CommandLine.command_with_result("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
37
+ when :stream
38
+ Dockistrano::CommandLine.command_with_stream("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
39
+ else
40
+ Dockistrano::CommandLine.command_with_interaction("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
41
+ end
42
+ end
43
+
44
+ def self.ps(options={})
45
+ execute(["ps", options])
46
+ end
47
+
48
+ def self.stop(id)
49
+ execute(["stop", id])
50
+ end
51
+
52
+ def self.run(full_image_name, options={})
53
+ if (command = options.delete(:command))
54
+ execute(["run", options, full_image_name, command])
55
+ else
56
+ execute(["run", options, full_image_name])
57
+ end
58
+ end
59
+
60
+ def self.exec(full_image_name, options={})
61
+ if (command = options.delete(:command))
62
+ execute(["run", options, full_image_name, command], :stream)
63
+ else
64
+ execute(["run", options, full_image_name], :stream)
65
+ end
66
+ end
67
+
68
+ def self.console(full_image_name, options={})
69
+ options["t"] = true
70
+ options["i"] = true
71
+ if (command = options.delete(:command))
72
+ execute(["run", options, full_image_name, command], :interaction)
73
+ else
74
+ execute(["run", options, full_image_name], :interaction)
75
+ end
76
+ end
77
+
78
+ def self.build(full_image_name)
79
+ execute(["build", { t: full_image_name }, "."], :stream)
80
+ end
81
+
82
+ def self.pull(full_image_name, tag)
83
+ execute(["pull", { t: tag }, full_image_name])
84
+ end
85
+
86
+ def self.push(image_name, tag)
87
+ execute(["push", image_name, tag], :stream)
88
+ end
89
+
90
+ def self.logs(id)
91
+ execute(["logs", id], :stream)
92
+ end
93
+
94
+ def self.attach(id)
95
+ execute(["attach", id], :stream)
96
+ end
97
+
98
+ def self.clean
99
+ Dockistrano::CommandLine.command_with_stream("#{docker_command} rmi $(#{docker_command} images -a | grep \"^<none>\" | awk '{print $3}')")
100
+ Dockistrano::CommandLine.command_with_stream("#{docker_command} rm $(#{docker_command} ps -a -q)")
101
+ end
102
+
103
+ def self.running_container_id(full_image_name)
104
+ request(["containers", "json"]).each do |container|
105
+ return container["Id"] if container["Image"] == full_image_name
106
+ end
107
+ nil
108
+ end
109
+
110
+ # Returns the id of the last container with an error
111
+ def self.last_run_container_id(full_image_name)
112
+ request(["containers", "json?all=1"]).each do |container|
113
+ return container["Id"] if container["Image"] == full_image_name and container["Command"] != "cat /dockistrano.yml"
114
+ end
115
+ nil
116
+ end
117
+
118
+ def self.image_id(full_image_name)
119
+ inspect_image(full_image_name)["id"]
120
+ end
121
+
122
+ class ImageNotFound < StandardError
123
+ end
124
+
125
+ def self.inspect_image(full_image_name)
126
+ response = request(["images", full_image_name, "json"])
127
+ rescue ResourceNotFound => e
128
+ raise ImageNotFound.new(e.message)
129
+ end
130
+
131
+ def self.inspect_container(id)
132
+ request(["containers", id, "json"])
133
+ end
134
+
135
+ def self.stop_all_containers_from_image(full_image_name)
136
+ containers = request(["containers", "json"])
137
+ containers.each do |container|
138
+ execute(["stop", container["Id"]]) if container["Image"] == full_image_name
139
+ end
140
+ end
141
+
142
+ def self.tags_for_image(image_name)
143
+ images = request(["images", "json"])
144
+ [].tap do |tags|
145
+ images.each do |image|
146
+ tags << image["Tag"] if image["Repository"] == image_name
147
+ end
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ def self.request(path)
154
+ uri = URI.parse("http://#{ENV['DOCKER_HOST_IP']}:4243/#{path.join("/")}")
155
+ response = Net::HTTP.get_response(uri)
156
+ if response.kind_of?(Net::HTTPNotFound)
157
+ raise ResourceNotFound.new("Could not find #{path.join("/")}: #{response.body}")
158
+ end
159
+
160
+ MultiJson.load(response.body)
161
+ end
162
+
163
+ class ResourceNotFound < StandardError
164
+ end
165
+
166
+ def self.arguments(options)
167
+ options.collect do |k,v|
168
+ case v
169
+ when TrueClass
170
+ "-#{k}"
171
+ when Array
172
+ v.collect { |av| "-#{k} #{av}" }.join(" ").strip
173
+ when Hash
174
+ v.collect { |ak, av|
175
+ if av
176
+ "-#{k} #{ak}='#{av}'"
177
+ else
178
+ ""
179
+ end
180
+ }.join(" ").strip
181
+ else
182
+ "-#{k} #{v}"
183
+ end
184
+ end.join(" ").strip
185
+ end
186
+
187
+ end
188
+ end
@@ -0,0 +1,27 @@
1
+ module Dockistrano
2
+
3
+ class Git
4
+
5
+ def self.repository_name
6
+ git_url = Cocaine::CommandLine.new("git config --get remote.origin.url").run.strip
7
+
8
+ if git_url =~ /^[A-z0-9]+@[A-z0-9.:\-]+\/([A-z0-9\-_\.]+)(\.git)?$/
9
+ $1.gsub(/\.git$/, "")
10
+ elsif git_url =~ /^https?:\/\/[a-z\-\.]+\/[a-z\-\.]+\/([A-z0-9.\-\_]+)$/
11
+ $1
12
+ else
13
+ raise "Unknown git url '#{git_url}'"
14
+ end
15
+ end
16
+
17
+ def self.branch
18
+ if ENV['JANKY_BRANCH']
19
+ ENV['JANKY_BRANCH'].gsub("/", "-")
20
+ else
21
+ branch = Cocaine::CommandLine.new("git rev-parse --abbrev-ref HEAD").run.strip
22
+ branch.gsub("/", "-")
23
+ end
24
+ end
25
+
26
+ end
27
+ end