ding 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/README.md +87 -0
- data/Rakefile +2 -0
- data/bin/ding +7 -0
- data/ding.gemspec +24 -0
- data/ding.png +0 -0
- data/lib/ding.rb +12 -0
- data/lib/ding/cli.rb +144 -0
- data/lib/ding/models/git.rb +99 -0
- data/lib/ding/models/ssh.rb +75 -0
- data/lib/ding/version.rb +3 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 152cdf9f3aabb65b05c06221910c6260db5f1034
|
4
|
+
data.tar.gz: d687eb4faa485a64a53521a68613f32f4c29bee5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37a8445e13983b973f6017ef464af96e8363f854aa3bec7fdf066a819db1ff867f32a2d1a301b4645d117a4311eec3ddc7ef15b3943d1f23d0113dfb6b9b32cd
|
7
|
+
data.tar.gz: d8e834a7f6aed324918085c708e879d3fbd570c611d47bc96cfc75ea99f9a49a4e89e2514045b6b3ebaece22330982067368dfc0940dfdcf88459578acd53cf7
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Ding
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Simple command line tool for deploying a specific feature branch of a
|
6
|
+
repo to a testing branch for driving CI deployment for QA.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
The usual method works:
|
11
|
+
|
12
|
+
gem install ding
|
13
|
+
|
14
|
+
## Configuration
|
15
|
+
|
16
|
+
By default, `ding` will create a branch called `testing` from the
|
17
|
+
selected feature branch. It also assumes that the master branch is
|
18
|
+
called `master`. Branches named `master` and `develop` cannot be deleted
|
19
|
+
by calling `Ding::Git.delete_branch` in code.
|
20
|
+
|
21
|
+
These defaults can be over-ridden by providing ENV vars to the shell:
|
22
|
+
|
23
|
+
DING_MASTER_BRANCH - main branch to switch to for synchronising
|
24
|
+
DING_TESTING_BRANCH - branch to over-ride from feature branch
|
25
|
+
DING_SACROSANCT_BRANCHES - space separated list of protected branches
|
26
|
+
|
27
|
+
## Using Ding
|
28
|
+
|
29
|
+
There are several commands available with global options for verbosity and forcing actions:
|
30
|
+
|
31
|
+
Commands:
|
32
|
+
ding help [COMMAND] # Describe available commands or one specific command
|
33
|
+
ding key-gen # Create a new private/public key pair and associated ssh config
|
34
|
+
ding key-show # Copy a public ssh key signature to the system clipboard (use -v to also display the signature)
|
35
|
+
ding test # Push a feature branch to the testing branch (this is the default action)
|
36
|
+
|
37
|
+
Options:
|
38
|
+
-f, [--force], [--no-force] # use the force on commands that allow it e.g. git push
|
39
|
+
-v, [--verbose], [--no-verbose] # show verbose output such as full callstack on errors
|
40
|
+
|
41
|
+
### ding test
|
42
|
+
|
43
|
+
This is the default action so running `ding` is the equivalent of `ding test`.
|
44
|
+
|
45
|
+
There is an option to specify the feature branch pattern to display for
|
46
|
+
selection of the code to be pushed to `testing`.
|
47
|
+
|
48
|
+
$ ding help test
|
49
|
+
|
50
|
+
Usage:
|
51
|
+
ding test
|
52
|
+
|
53
|
+
Options:
|
54
|
+
-p, [--pattern=PATTERN] # specify a pattern for listing branches
|
55
|
+
# Default: origin/XAP*
|
56
|
+
|
57
|
+
Push a feature branch to the testing branch
|
58
|
+
|
59
|
+
### ding key-gen
|
60
|
+
|
61
|
+
This will generate a new ssh key pair and configure them into the ssh config
|
62
|
+
for the relevant host. This allows `ding test` to push code to bitbucket.org,
|
63
|
+
for example, so that you aren't prompted for a userid and password each
|
64
|
+
time.
|
65
|
+
|
66
|
+
On completion, the public key is copied to the system clipboard so that
|
67
|
+
it can be pasted into the users account on bitbucket.org.
|
68
|
+
|
69
|
+
Usage:
|
70
|
+
ding key-gen
|
71
|
+
|
72
|
+
Options:
|
73
|
+
-h, [--host=HOST] # specify repository host for ssh config
|
74
|
+
# Default: bitbucket.org
|
75
|
+
-n, [--name=NAME] # name for key, defaults to host name
|
76
|
+
-p, [--passphrase=PASSPHRASE] # optional passphrase for key
|
77
|
+
-t, [--type=TYPE] # type of key to create per -t option on ssh-keygen
|
78
|
+
# Default: rsa
|
79
|
+
|
80
|
+
Create a new private/public key pair and associated ssh config
|
81
|
+
|
82
|
+
### ding key-show
|
83
|
+
|
84
|
+
If the public key is needed again for pasting into the bitbucket.org config it can be
|
85
|
+
captured on the clipboard by running this command and selecting the appropriate key from
|
86
|
+
the list presented.
|
87
|
+
|
data/Rakefile
ADDED
data/bin/ding
ADDED
data/ding.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ding/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'ding'
|
8
|
+
spec.version = Ding::VERSION
|
9
|
+
spec.authors = ['Warren Bain']
|
10
|
+
spec.email = ['warren@thoughtcroft.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Push specific feature branch code to a testing branch}
|
13
|
+
spec.description = %q{Push specific feature branch code to a testing branch}
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
spec.add_runtime_dependency 'thor', '~> 0.19'
|
23
|
+
spec.add_runtime_dependency 'git-up'
|
24
|
+
end
|
data/ding.png
ADDED
Binary file
|
data/lib/ding.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'ding/version'
|
2
|
+
require 'ding/cli'
|
3
|
+
require 'ding/models/git'
|
4
|
+
require 'ding/models/ssh'
|
5
|
+
|
6
|
+
module Ding
|
7
|
+
MASTER_BRANCH = ENV['DING_MASTER_BRANCH'] || 'master'
|
8
|
+
TESTING_BRANCH = ENV['DING_TESTING_BRANCH'] || 'testing'
|
9
|
+
SACROSANCT_BRANCHES = (ENV['DING_SACROSANCT_BRANCHES'] || 'master develop').split
|
10
|
+
|
11
|
+
# because we lurve the command line... ding!
|
12
|
+
end
|
data/lib/ding/cli.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Ding
|
5
|
+
class Cli < Thor
|
6
|
+
class_option :force, type: 'boolean', aliases: '-f', default: false, desc: 'use the force on commands that allow it e.g. git push'
|
7
|
+
class_option :verbose, type: 'boolean', aliases: '-v', default: false, desc: 'show verbose output such as full callstack on errors'
|
8
|
+
|
9
|
+
default_task :test
|
10
|
+
|
11
|
+
desc "test", "Push a feature branch to the testing branch (this is the default action)"
|
12
|
+
option :pattern, type: 'string', aliases: '-p', default: 'origin/XAP*', desc: 'specify a pattern for listing branches'
|
13
|
+
def test
|
14
|
+
master_branch, testing_branch = Ding::MASTER_BRANCH.dup, Ding::TESTING_BRANCH.dup
|
15
|
+
say "\nDing ding ding: let's push a feature branch to #{testing_branch}...\n\n", :green
|
16
|
+
|
17
|
+
repo = Ding::Git.new(options).tap do |r|
|
18
|
+
say "> Synchronising with the remote...", :green
|
19
|
+
r.checkout master_branch
|
20
|
+
r.update
|
21
|
+
end
|
22
|
+
|
23
|
+
branches = repo.branches(options[:pattern])
|
24
|
+
if branches.empty?
|
25
|
+
say "\n --> No feature branches available to test, I'm out of here!\n\n", :red
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
feature_branch = ask_which_item(branches, 'Which feature branch should I use?')
|
30
|
+
|
31
|
+
repo.tap do |r|
|
32
|
+
say "\n> Deleting #{testing_branch}...", :green
|
33
|
+
r.delete_branch(testing_branch)
|
34
|
+
say "> Checking out #{feature_branch}...", :green
|
35
|
+
r.checkout(feature_branch)
|
36
|
+
say "> Creating #{testing_branch}...", :green
|
37
|
+
r.create_branch(testing_branch)
|
38
|
+
say "> Pushing #{testing_branch} to the remote...", :green
|
39
|
+
r.push(testing_branch)
|
40
|
+
end
|
41
|
+
|
42
|
+
rescue => e
|
43
|
+
show_error e
|
44
|
+
else
|
45
|
+
say "\n --> I'm finished: ding ding ding!\n\n", :green
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "key-gen", "Create a new private/public key pair and associated ssh config"
|
49
|
+
option :host, type: 'string', aliases: '-h', default: 'bitbucket.org', desc: 'specify repository host for ssh config'
|
50
|
+
option :name, type: 'string', aliases: '-n', default: nil, desc: 'name for key, defaults to host name'
|
51
|
+
option :passphrase, type: 'string', aliases: '-p', default: '', desc: 'optional passphrase for key'
|
52
|
+
option :type, type: 'string', aliases: '-t', default: 'rsa', desc: 'type of key to create per -t option on ssh-keygen'
|
53
|
+
def key_gen
|
54
|
+
key_name = options[:name] || "#{options[:host]}_#{options[:type]}"
|
55
|
+
say "\nDing ding ding: let's create and configure a new ssh key #{key_name}...\n\n", :green
|
56
|
+
|
57
|
+
Ding::Ssh.new(options).tap do |s|
|
58
|
+
if s.ssh_key_exists?(key_name)
|
59
|
+
if yes?("Do you want me to replace the existing key?", :yellow)
|
60
|
+
say "> Removing existing key #{key_name}...", :cyan
|
61
|
+
s.delete_ssh_key key_name
|
62
|
+
say "> Creating the replacement ssh key pair...", :cyan
|
63
|
+
s.create_ssh_key key_name, ENV['USER']
|
64
|
+
else
|
65
|
+
say "> Using existing key #{key_name}...", :cyan
|
66
|
+
end
|
67
|
+
else
|
68
|
+
say "> Creating the new ssh key pair...", :green
|
69
|
+
s.create_ssh_key key_name, ENV['USER']
|
70
|
+
end
|
71
|
+
say "> Adding the private key to the ssh config...", :green
|
72
|
+
s.update_config options[:host], key_name
|
73
|
+
say "> Copying the public key to the clipboard...", :green
|
74
|
+
copy_file_to_clipboard s.ssh_public_key_file(key_name)
|
75
|
+
end
|
76
|
+
|
77
|
+
rescue => e
|
78
|
+
show_error e
|
79
|
+
else
|
80
|
+
say "\n --> I'm finished: ding ding ding!\n\n", :green
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "key-show", "Copy a public ssh key signature to the system clipboard (use -v to also display the signature)"
|
84
|
+
def key_show
|
85
|
+
say "\nDing ding ding: let's copy a public key to the clipboard...\n\n", :green
|
86
|
+
|
87
|
+
Ding::Ssh.new(options).tap do |s|
|
88
|
+
key_name = ask_which_item(s.list_ssh_keys, 'Which key do you want to copy?')
|
89
|
+
say "\n> Copying the public key to the clipboard...", :green
|
90
|
+
copy_file_to_clipboard s.ssh_public_key_file(key_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
rescue => e
|
94
|
+
show_error e
|
95
|
+
else
|
96
|
+
say "\n --> You can now Command-V to paste that key: ding ding ding!\n\n", :green
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def show_error(e)
|
102
|
+
say "\n --> Error: #{e.message}\n\n", :red
|
103
|
+
raise if options[:verbose]
|
104
|
+
exit 1
|
105
|
+
end
|
106
|
+
|
107
|
+
def ask_which_item(items, prompt)
|
108
|
+
return items.first if items.size == 1
|
109
|
+
str_format = "\n %#{items.count.to_s.size}s: %s"
|
110
|
+
question = set_color prompt, :yellow
|
111
|
+
answers = {}
|
112
|
+
|
113
|
+
items.each_with_index do |item, index|
|
114
|
+
i = (index + 1).to_s
|
115
|
+
answers[i] = item
|
116
|
+
question << format(str_format, i, item)
|
117
|
+
end
|
118
|
+
|
119
|
+
say question
|
120
|
+
reply = ask("> ").to_s
|
121
|
+
if answers[reply]
|
122
|
+
answers[reply]
|
123
|
+
else
|
124
|
+
say "\n --> That's not a valid selection, I'm out of here!\n\n", :red
|
125
|
+
exit 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def copy_file_to_clipboard(file)
|
130
|
+
cmd = "cat #{file} | "
|
131
|
+
if options[:verbose]
|
132
|
+
cmd << 'tee >(pbcopy)'
|
133
|
+
else
|
134
|
+
cmd << ' pbcopy'
|
135
|
+
end
|
136
|
+
bash cmd
|
137
|
+
end
|
138
|
+
|
139
|
+
def bash(cmd)
|
140
|
+
escaped_cmd = Shellwords.escape cmd
|
141
|
+
system "bash -c #{escaped_cmd}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Ding
|
2
|
+
class Git
|
3
|
+
|
4
|
+
def initialize(options={})
|
5
|
+
raise "#{repo} is NOT a git repository" unless git_repo?
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def branches(pattern)
|
10
|
+
%x(git branch --remote --list #{remote_version(pattern)}).split.map {|b| b.split('/').last}
|
11
|
+
end
|
12
|
+
|
13
|
+
def branch_exists?(branch)
|
14
|
+
! %x(git branch --list #{branch}).empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def checkout(branch)
|
18
|
+
raise "Unable to checkout #{branch}" unless run_cmd "git checkout #{branch}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_branch(branch)
|
22
|
+
raise "Unable to create #{branch}" unless run_cmd "git branch --track #{branch}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete_branch(branch)
|
26
|
+
local_branch = local_version(branch)
|
27
|
+
remote_branch = remote_version(branch)
|
28
|
+
raise "You are not allowed to delete #{local_branch}" if Ding::SACROSANCT_BRANCHES.include?(local_branch)
|
29
|
+
if branch_exists?(local_branch)
|
30
|
+
branch_cmd = "git branch #{options[:force] ? '-D' : '-d'} #{local_branch}"
|
31
|
+
raise "Unable to delete #{local_branch}" unless run_cmd branch_cmd
|
32
|
+
end
|
33
|
+
if branch_exists?(remote_branch)
|
34
|
+
branch_cmd = "git push #{remote_name} :#{local_branch} #{options[:force] ? '-f' : ''}"
|
35
|
+
raise "Unable to delete #{remote_branch}" unless run_cmd branch_cmd
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def push(branch)
|
40
|
+
checkout branch
|
41
|
+
push_cmd = "git push #{remote_name} #{branch}"
|
42
|
+
push_cmd << " --force" if options[:force]
|
43
|
+
raise "Unable to push #{branch} branch!" unless run_cmd push_cmd
|
44
|
+
end
|
45
|
+
|
46
|
+
def update
|
47
|
+
raise "Error synchronising with the remote" unless run_cmd "git up"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def git_repo?
|
53
|
+
run_cmd "git status"
|
54
|
+
end
|
55
|
+
|
56
|
+
def repo
|
57
|
+
@repo || Dir.pwd
|
58
|
+
end
|
59
|
+
|
60
|
+
def remote_version(branch)
|
61
|
+
if is_remote?(branch)
|
62
|
+
branch
|
63
|
+
else
|
64
|
+
"#{remote_prefix}#{branch}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def local_version(branch)
|
69
|
+
if is_remote?(branch)
|
70
|
+
branch.gsub(remote_name, '')
|
71
|
+
else
|
72
|
+
branch
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def is_remote?(branch)
|
77
|
+
branch.start_with?(remote_prefix)
|
78
|
+
end
|
79
|
+
|
80
|
+
def remote_name
|
81
|
+
@remote_name || %x(git remote).chomp
|
82
|
+
end
|
83
|
+
|
84
|
+
def remote_prefix
|
85
|
+
"#{remote_name}/"
|
86
|
+
end
|
87
|
+
|
88
|
+
# NOTE: only for commands where we are interested in the effect
|
89
|
+
# as unless verbose is turned on, stdout and stderr are suppressed
|
90
|
+
def run_cmd(cmd)
|
91
|
+
cmd << ' &>/dev/null ' unless options[:verbose]
|
92
|
+
system cmd
|
93
|
+
end
|
94
|
+
|
95
|
+
def options
|
96
|
+
@options || {}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Ding
|
4
|
+
class Ssh
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def list_ssh_keys
|
11
|
+
Dir.glob(File.join(ssh_config_path, '*.pub')).map {|f| File.basename f, '.pub'}
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_ssh_key(name, comment)
|
15
|
+
raise "ssh key #{name} already exists!" if ssh_key_exists? name
|
16
|
+
run_cmd "ssh-keygen -t #{options[:type]} -C #{comment} -P '#{options[:passphrase]}' -f #{File.join(ssh_config_path, name)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete_ssh_key(name)
|
20
|
+
File.delete ssh_public_key_file(name), ssh_private_key_file(name) if ssh_key_exists? name
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_config(host, name)
|
24
|
+
if File.exists?(ssh_config_file)
|
25
|
+
config = File.open(ssh_config_file).read
|
26
|
+
raise "Host #{host} already configured in ssh config" if config.include?(host)
|
27
|
+
raise "Key #{name} already configured in ssh config" if config.include?(name)
|
28
|
+
else
|
29
|
+
FileUtils.mkdir_p ssh_config_path
|
30
|
+
end
|
31
|
+
|
32
|
+
File.open(ssh_config_file, 'a') do |f|
|
33
|
+
f.puts "Host #{host}"
|
34
|
+
f.puts " IdentityFile #{ssh_private_key_file name}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def ssh_key_exists?(name)
|
39
|
+
File.exists? ssh_private_key_file(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def ssh_private_key_file(name)
|
43
|
+
File.join ssh_config_path, name
|
44
|
+
end
|
45
|
+
|
46
|
+
def ssh_public_key_file(name)
|
47
|
+
"#{ssh_private_key_file name}.pub"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def ssh_config_exists?
|
53
|
+
File.exists? ssh_config_file
|
54
|
+
end
|
55
|
+
|
56
|
+
def ssh_config_path
|
57
|
+
@ssh_config_path || options[:ssh_config_path] || File.join(ENV['HOME'], '.ssh')
|
58
|
+
end
|
59
|
+
|
60
|
+
def ssh_config_file
|
61
|
+
@ssh_config_file || options[:ssh_config_file] || File.join(ssh_config_path, 'config')
|
62
|
+
end
|
63
|
+
|
64
|
+
# NOTE: only for commands where we are interested in the effect
|
65
|
+
# as unless verbose is turned on, stdout and stderr are suppressed
|
66
|
+
def run_cmd(cmd)
|
67
|
+
cmd << ' &>/dev/null ' unless options[:verbose]
|
68
|
+
system cmd
|
69
|
+
end
|
70
|
+
|
71
|
+
def options
|
72
|
+
@options || {}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/ding/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ding
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Warren Bain
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.19'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.19'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: git-up
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Push specific feature branch code to a testing branch
|
70
|
+
email:
|
71
|
+
- warren@thoughtcroft.com
|
72
|
+
executables:
|
73
|
+
- ding
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- Gemfile
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/ding
|
84
|
+
- ding.gemspec
|
85
|
+
- ding.png
|
86
|
+
- lib/ding.rb
|
87
|
+
- lib/ding/cli.rb
|
88
|
+
- lib/ding/models/git.rb
|
89
|
+
- lib/ding/models/ssh.rb
|
90
|
+
- lib/ding/version.rb
|
91
|
+
homepage:
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.4.5
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: Push specific feature branch code to a testing branch
|
115
|
+
test_files: []
|