coaster 1.3.32 → 1.3.33
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 +4 -4
- data/bin/coaster +1 -1
- data/lib/coaster/cmd_options.rb +159 -0
- data/lib/coaster/git/options.rb +118 -0
- data/lib/coaster/git/repository.rb +68 -81
- data/lib/coaster/git.rb +20 -0
- data/lib/coaster/version.rb +1 -1
- data/test/test_git.rb +0 -48
- data/test/test_git_options.rb +32 -0
- data/test/test_git_repository.rb +64 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 684eb09e07b2184d93f7dd1ba8ef28df6d75c29bbaac226e4e513da16e0d22f5
|
|
4
|
+
data.tar.gz: 5479f75d9364214c164b022a7fc2fb96802c7258663909b16afbdcb75d45ad8e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58f78f7427f2069f3c69389f23dfec8140c365f0d9817e8ee71cc00db978365344d2f4b109acc9268889150509ce63ae56f6b02f087915815ac6d91e5b91e183
|
|
7
|
+
data.tar.gz: 3e70c07f05f01312fd95a33b711ea7bd4289db6e4e447392250a8c22568ed8af236456c80f3846ae530621e1038320b70a5f11d74d269a99f13b0bed32b81879
|
data/bin/coaster
CHANGED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
module Coaster
|
|
2
|
+
class CmdOptions
|
|
3
|
+
class << self
|
|
4
|
+
def options_to_s(options)
|
|
5
|
+
case options
|
|
6
|
+
when Hash then options_h_to_s(options)
|
|
7
|
+
when Array, Set then options.map{|o| options_to_s(o)}.join(' ')
|
|
8
|
+
else options
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def options_s_to_h(options)
|
|
13
|
+
opts = {}
|
|
14
|
+
options = " #{options}"
|
|
15
|
+
options_indexes = options.enum_for(:scan, / -\w| --\w+| -- /).map { Regexp.last_match.begin(0) }
|
|
16
|
+
options_indexes << 0
|
|
17
|
+
options_indexes.each_cons(2) do |a, b|
|
|
18
|
+
option = options[a+1..b-1]
|
|
19
|
+
h = option_s_to_h(option)
|
|
20
|
+
options_h_merger(h, base: opts)
|
|
21
|
+
end
|
|
22
|
+
opts
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def option_s_to_h(option)
|
|
26
|
+
if option.start_with?(/--\w/)
|
|
27
|
+
opt = option.split('=', 2)
|
|
28
|
+
opt << '' if opt.length == 1
|
|
29
|
+
elsif option.start_with?(/-\w/)
|
|
30
|
+
opt = option.split(' ', 2)
|
|
31
|
+
opt << '' if opt.length == 1
|
|
32
|
+
elsif option.start_with?('-- ')
|
|
33
|
+
opt = ['--', option[3..-1].split(' ')]
|
|
34
|
+
else
|
|
35
|
+
return {}
|
|
36
|
+
end
|
|
37
|
+
opt[1] = opt[1].split(',') if opt[1].include?(',')
|
|
38
|
+
opt[1] = opt[1].map{|s| s.include?('=') ? Hash[s.split('=', 2)] : s}.to_h if opt[1].is_a?(Array)
|
|
39
|
+
[opt].to_h
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def option_v_to_s(option_v)
|
|
43
|
+
case option_v
|
|
44
|
+
when Hash then option_v.map{|vk,vv| Set[vk, vv]}.to_set
|
|
45
|
+
when Array then option_v.map{|v| option_v_to_s(v)}.join(',')
|
|
46
|
+
when Set then option_v.map{|v| option_v_to_s(v)}.join('=')
|
|
47
|
+
else
|
|
48
|
+
option_v = (option_v || '').to_s
|
|
49
|
+
option_v = option_v.gsub(/"/, '\"')
|
|
50
|
+
option_v = "\"#{option_v}\"" if option_v.include?(' ')
|
|
51
|
+
option_v
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def options_h_to_s(options)
|
|
56
|
+
opts = []
|
|
57
|
+
|
|
58
|
+
# multiple options can be passed by set
|
|
59
|
+
options.map do |k, v|
|
|
60
|
+
if v.is_a?(Set)
|
|
61
|
+
v.each {|set_v| opts << [k, set_v]}
|
|
62
|
+
else
|
|
63
|
+
opts << [k, v]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
targets = ''
|
|
68
|
+
parsed = opts.map do |k, v|
|
|
69
|
+
if k.start_with?(/--\w/)
|
|
70
|
+
v = option_v_to_s(v)
|
|
71
|
+
if v.is_a?(Set)
|
|
72
|
+
v.map {|vv| "#{k}=#{option_v_to_s(vv)}" }.join(' ')
|
|
73
|
+
else
|
|
74
|
+
"#{k}#{v.length > 0 ? "=#{v}" : ''}" # ex, --config-env=<name>=<envvar>
|
|
75
|
+
end
|
|
76
|
+
elsif k.start_with?(/-\w/)
|
|
77
|
+
v = option_v_to_s(v)
|
|
78
|
+
if v.is_a?(Set)
|
|
79
|
+
v.map {|vv| "#{k} #{option_v_to_s(vv)}"}.join(' ')
|
|
80
|
+
else
|
|
81
|
+
"#{k} #{v}" # ex, -c <name>=<value>
|
|
82
|
+
end
|
|
83
|
+
elsif k == '--'
|
|
84
|
+
if v.present?
|
|
85
|
+
v = Array.wrap(v)
|
|
86
|
+
v = v.map{|e| option_v_to_s(e)}.join(' ')
|
|
87
|
+
targets = "-- #{v}" # ex, -- <args>
|
|
88
|
+
''
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
raise "Unknown option: #{k}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
parsed << targets
|
|
96
|
+
parsed.join(' ')
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
attr_accessor :repository
|
|
101
|
+
|
|
102
|
+
def initialize(cmd, *args, **options)
|
|
103
|
+
arg_options = args.extract_options!
|
|
104
|
+
options = options.merge(arg_options)
|
|
105
|
+
@cmd = cmd
|
|
106
|
+
@cmd, @sub_cmd = @cmd if @cmd.is_a?(Array)
|
|
107
|
+
remain_ix = args.index{ |k| k == '--'}
|
|
108
|
+
if remain_ix
|
|
109
|
+
@remain_args = args[remain_ix+1..-1]
|
|
110
|
+
@args = args[0...remain_ix]
|
|
111
|
+
else
|
|
112
|
+
@args = args
|
|
113
|
+
end
|
|
114
|
+
if @args.first.is_a?(self.class)
|
|
115
|
+
options = @args.first.to_h.merge(options)
|
|
116
|
+
end
|
|
117
|
+
if @args.last.is_a?(self.class)
|
|
118
|
+
options = @args.last.to_h.merge(options)
|
|
119
|
+
end
|
|
120
|
+
options['--'] ||= []
|
|
121
|
+
options['--'] += @remain_args if @remain_args
|
|
122
|
+
@options = options
|
|
123
|
+
@args << self.class.options_to_s(options).strip
|
|
124
|
+
@str = @args.join(' ')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def parser_proc(*args)
|
|
128
|
+
raise 'Not implemented'
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def parser
|
|
132
|
+
parser_proc = parser_proc(@cmd, @sub_cmd)
|
|
133
|
+
instance_exec(&parser_proc)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def to_h
|
|
137
|
+
return @hash if defined?(@hash)
|
|
138
|
+
@hash = {}
|
|
139
|
+
remain_args = parser.parse!(@str.split(' '))
|
|
140
|
+
@hash['--'] = remain_args if remain_args.any?
|
|
141
|
+
@hash
|
|
142
|
+
end
|
|
143
|
+
delegate :[], :[]=, :key?, :map, :each, to: :to_h
|
|
144
|
+
|
|
145
|
+
def merge(*args, **options)
|
|
146
|
+
if args.first.is_a?(CmdOptions)
|
|
147
|
+
other = args.shift
|
|
148
|
+
else
|
|
149
|
+
other = self.class.new([@cmd, @sub_cmd], *args, **options)
|
|
150
|
+
end
|
|
151
|
+
self.class.new(to_h.merge(other.to_h))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def to_s
|
|
155
|
+
return self.class.options_h_to_s(@hash) if defined?(@hash)
|
|
156
|
+
@str
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'coaster/cmd_options'
|
|
2
|
+
|
|
3
|
+
module Coaster
|
|
4
|
+
module Git
|
|
5
|
+
class Options < ::Coaster::CmdOptions
|
|
6
|
+
OPTION_PARSER = {
|
|
7
|
+
'git' => {
|
|
8
|
+
nil => proc do
|
|
9
|
+
OptionParser.new do |opts|
|
|
10
|
+
opts.on('-c', '--config-env=NAME=VALUE') { |v|
|
|
11
|
+
name, envvar = v.split('=')
|
|
12
|
+
@hash['--config-env'] ||= {}
|
|
13
|
+
@hash['--config-env'][name] = envvar
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end,
|
|
17
|
+
},
|
|
18
|
+
'config' => {
|
|
19
|
+
nil => proc do
|
|
20
|
+
OptionParser.new do |opts|
|
|
21
|
+
end
|
|
22
|
+
end,
|
|
23
|
+
},
|
|
24
|
+
'status' => {
|
|
25
|
+
nil => proc do
|
|
26
|
+
OptionParser.new do |opts|
|
|
27
|
+
end
|
|
28
|
+
end,
|
|
29
|
+
},
|
|
30
|
+
'add' => {
|
|
31
|
+
nil => proc do
|
|
32
|
+
OptionParser.new do |opts|
|
|
33
|
+
end
|
|
34
|
+
end,
|
|
35
|
+
},
|
|
36
|
+
'commit' => {
|
|
37
|
+
nil => proc do
|
|
38
|
+
OptionParser.new do |opts|
|
|
39
|
+
opts.on('-m', '--message') { |v| @hash['--message'] = v }
|
|
40
|
+
end
|
|
41
|
+
end,
|
|
42
|
+
},
|
|
43
|
+
'fetch' => {
|
|
44
|
+
nil => proc do
|
|
45
|
+
OptionParser.new do |opts|
|
|
46
|
+
end
|
|
47
|
+
end,
|
|
48
|
+
},
|
|
49
|
+
'branch' => {
|
|
50
|
+
nil => proc do
|
|
51
|
+
OptionParser.new do |opts|
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
},
|
|
55
|
+
'checkout' => {
|
|
56
|
+
nil => proc do
|
|
57
|
+
OptionParser.new do |opts|
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
},
|
|
61
|
+
'merge' => {
|
|
62
|
+
nil => proc do
|
|
63
|
+
OptionParser.new do |opts|
|
|
64
|
+
opts.on('-m', '--message') { |v| @hash['--message'] = v }
|
|
65
|
+
opts.on('--no-commit') { |v| @hash['--no-commit'] = '' }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
},
|
|
69
|
+
'log' => {
|
|
70
|
+
nil => proc do
|
|
71
|
+
OptionParser.new do |opts|
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
},
|
|
75
|
+
'diff' => {
|
|
76
|
+
nil => proc do
|
|
77
|
+
OptionParser.new do |opts|
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
},
|
|
81
|
+
'submodule' => {
|
|
82
|
+
nil => proc do
|
|
83
|
+
OptionParser.new do |opts|
|
|
84
|
+
end
|
|
85
|
+
end,
|
|
86
|
+
'add' => proc do
|
|
87
|
+
OptionParser.new do |opts|
|
|
88
|
+
end
|
|
89
|
+
end,
|
|
90
|
+
'init' => proc do
|
|
91
|
+
OptionParser.new do |opts|
|
|
92
|
+
end
|
|
93
|
+
end,
|
|
94
|
+
'update' => proc do
|
|
95
|
+
OptionParser.new do |opts|
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
},
|
|
99
|
+
'ls-tree' => {
|
|
100
|
+
nil => proc do
|
|
101
|
+
OptionParser.new do |opts|
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
},
|
|
105
|
+
'rev-parse' => {
|
|
106
|
+
nil => proc do
|
|
107
|
+
OptionParser.new do |opts|
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
def parser_proc(cmd, sub_cmd, *args)
|
|
114
|
+
OPTION_PARSER[cmd][sub_cmd]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -1,104 +1,67 @@
|
|
|
1
1
|
module Coaster
|
|
2
2
|
module Git
|
|
3
3
|
class Repository
|
|
4
|
-
|
|
5
|
-
def option_parser(options)
|
|
6
|
-
case options
|
|
7
|
-
when Hash then hash_option_parser(options)
|
|
8
|
-
when Array, Set then options.map{|o| option_parser(o)}.join(' ')
|
|
9
|
-
else options
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def hash_option_parser(options)
|
|
14
|
-
opts = []
|
|
15
|
-
|
|
16
|
-
# multiple options can be passed by set
|
|
17
|
-
options.map do |k, v|
|
|
18
|
-
if v.is_a?(Set)
|
|
19
|
-
v.each {|set_v| opts << [k, set_v]}
|
|
20
|
-
else
|
|
21
|
-
opts << [k, v]
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
parsed = opts.map do |k, v|
|
|
26
|
-
v = case v
|
|
27
|
-
when Hash then v.map{|vk,vv| "#{vk}=#{vv}"}.join(',')
|
|
28
|
-
when Array then v.join(',')
|
|
29
|
-
else v || ''
|
|
30
|
-
end
|
|
31
|
-
v = v.strip
|
|
32
|
-
if k.start_with?('--')
|
|
33
|
-
"#{k}#{v.length > 0 ? "=#{v}" : ''}" # ex, --config-env=<name>=<envvar>
|
|
34
|
-
else
|
|
35
|
-
"#{k} #{v.length > 0 ? "#{v}" : ''}" # ex, -c <name>=<value>
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
parsed.join(' ')
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def run_cmd(path, command)
|
|
43
|
-
puts "#{path}: #{command}"
|
|
44
|
-
stdout, stderr, status = Open3.capture3(command, chdir: path)
|
|
45
|
-
if status.success?
|
|
46
|
-
puts " ↳ success: #{stdout}"
|
|
47
|
-
stdout
|
|
48
|
-
else
|
|
49
|
-
raise "Error executing command: #{command}\n ↳ #{stderr}"
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def create(path)
|
|
54
|
-
run_cmd(path.split('/')[0..-2].join('/'), "git init #{path}")
|
|
55
|
-
run_cmd(path, "git commit --allow-empty -m 'initial commit'")
|
|
56
|
-
new(path)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
4
|
+
include Coaster::Git
|
|
59
5
|
|
|
60
6
|
attr_reader :path
|
|
61
7
|
|
|
62
8
|
def initialize(path)
|
|
63
9
|
@path = path
|
|
64
|
-
@sha = current_sha
|
|
65
10
|
end
|
|
66
11
|
|
|
67
|
-
def run_cmd(command)
|
|
68
|
-
|
|
12
|
+
def run_cmd(command, path: nil)
|
|
13
|
+
super(path || @path, command)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def with_git_options(*args, **options, &block)
|
|
17
|
+
@git_options = Options.new('git', *args, **options)
|
|
18
|
+
yield
|
|
19
|
+
@git_options = nil
|
|
69
20
|
end
|
|
70
21
|
|
|
71
|
-
def run_git_cmd(command, *options)
|
|
72
|
-
|
|
22
|
+
def run_git_cmd(command, *args, **options)
|
|
23
|
+
opts = Options.new(command, *args, **options)
|
|
24
|
+
cmd = "git #{@git_options} #{Array.wrap(command).join(' ')} #{opts}"
|
|
73
25
|
run_cmd(cmd)
|
|
74
26
|
end
|
|
75
27
|
|
|
76
28
|
def add(*paths, **options)
|
|
77
|
-
|
|
29
|
+
opts = Options.new('add', **options)
|
|
30
|
+
run_git_cmd("add", *paths, opts)
|
|
78
31
|
end
|
|
79
32
|
|
|
80
|
-
def commit(
|
|
81
|
-
|
|
33
|
+
def commit(*args, **options)
|
|
34
|
+
opts = Options.new('commit', *options)
|
|
35
|
+
opts['--message'] ||= "no message"
|
|
36
|
+
run_git_cmd("commit", opts)
|
|
82
37
|
end
|
|
83
38
|
|
|
84
|
-
def branch(
|
|
85
|
-
run_git_cmd("branch
|
|
39
|
+
def branch(*args, **options)
|
|
40
|
+
run_git_cmd("branch", *args, **options)
|
|
86
41
|
end
|
|
87
42
|
|
|
88
|
-
def checkout(
|
|
89
|
-
run_git_cmd("checkout
|
|
43
|
+
def checkout(*args, **options)
|
|
44
|
+
run_git_cmd("checkout", *args, **options)
|
|
90
45
|
end
|
|
91
46
|
|
|
92
|
-
def submodule_add!(path,
|
|
93
|
-
run_git_cmd("submodule add
|
|
47
|
+
def submodule_add!(repo, path, *args, **options)
|
|
48
|
+
run_git_cmd(["submodule", 'add'], repo, path, *args, **options)
|
|
94
49
|
end
|
|
95
50
|
|
|
96
|
-
def submodule_init!(
|
|
97
|
-
run_git_cmd("submodule init
|
|
51
|
+
def submodule_init!(*paths)
|
|
52
|
+
run_git_cmd(["submodule", "init"], *paths)
|
|
98
53
|
end
|
|
99
54
|
|
|
100
|
-
def submodule_update!(*paths, options
|
|
101
|
-
run_git_cmd("submodule update
|
|
55
|
+
def submodule_update!(*paths, **options)
|
|
56
|
+
run_git_cmd(["submodule", "update"], *paths, **options)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def fetch(*args, **options)
|
|
60
|
+
run_git_cmd("fetch", *args, **options)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def status(*args, **options)
|
|
64
|
+
run_git_cmd("status", *args, **options)
|
|
102
65
|
end
|
|
103
66
|
|
|
104
67
|
def current_sha
|
|
@@ -117,33 +80,57 @@ module Coaster
|
|
|
117
80
|
end.to_h
|
|
118
81
|
end
|
|
119
82
|
|
|
120
|
-
def merge(pointer)
|
|
83
|
+
def merge(pointer, *args, **options)
|
|
84
|
+
opts = Options.new('merge', *args, **options)
|
|
121
85
|
pointers = pointers(pointer).join(',')
|
|
122
|
-
puts "#{path}
|
|
123
|
-
|
|
86
|
+
puts "[MERGE] #{path} #{pointers} #{options}"
|
|
87
|
+
opts['--message'] ||= "Merge #{pointers}"
|
|
88
|
+
run_git_cmd("merge #{pointer} #{opts}")
|
|
124
89
|
end
|
|
125
90
|
|
|
126
91
|
def submodule_sha(path, pointer: nil)
|
|
127
|
-
pointer ||=
|
|
92
|
+
pointer ||= current_sha
|
|
128
93
|
run_git_cmd("ls-tree #{pointer} #{path}").split(' ')[2]
|
|
129
94
|
end
|
|
130
95
|
|
|
96
|
+
def merge_without_submodules
|
|
97
|
+
run_git_cmd('config merge.ours.name "Keep ours merge driver"')
|
|
98
|
+
run_git_cmd('config merge.ours.driver true')
|
|
99
|
+
ga_file = File.join(@path, '.gitattributes')
|
|
100
|
+
run_cmd("touch #{ga_file}")
|
|
101
|
+
ga_lines = File.read(ga_file).split("\n")
|
|
102
|
+
ga_lines_appended = ga_lines + submodules.keys.map{|sb_path| "#{sb_path} merge=ours" }
|
|
103
|
+
File.open(ga_file, 'w') do |f|
|
|
104
|
+
f.puts ga_lines_appended.join("\n")
|
|
105
|
+
end
|
|
106
|
+
add('.')
|
|
107
|
+
commit
|
|
108
|
+
yield
|
|
109
|
+
File.open(ga_file, 'w') do |f|
|
|
110
|
+
f.puts ga_lines.join("\n")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
131
114
|
def deep_merge(pointer)
|
|
115
|
+
puts "[DEEP_MERGE] #{path} #{pointer}"
|
|
132
116
|
submodules.values.each do |submodule|
|
|
133
117
|
sm_sha = submodule_sha(submodule.path, pointer: pointer)
|
|
134
118
|
submodule.merge(sm_sha)
|
|
135
119
|
end
|
|
136
|
-
|
|
120
|
+
merge_without_submodules do
|
|
121
|
+
merge(pointer)
|
|
122
|
+
end
|
|
137
123
|
end
|
|
138
124
|
|
|
139
125
|
def pointers(sha)
|
|
140
126
|
run_git_cmd("branch --contains #{sha}").split("\n").map do |br|
|
|
141
|
-
(br.start_with?('*') ? br[2..-1] : br).strip
|
|
142
|
-
|
|
127
|
+
br = (br.start_with?('*') ? br[2..-1] : br).strip
|
|
128
|
+
br.match?(/^\(.*\)$/) ? nil : br
|
|
129
|
+
end.compact
|
|
143
130
|
end
|
|
144
131
|
|
|
145
132
|
def remove
|
|
146
|
-
|
|
133
|
+
run_cmd("rm -rf #{path}", path: path.split('/')[0..-2].join('/'))
|
|
147
134
|
end
|
|
148
135
|
end
|
|
149
136
|
end
|
data/lib/coaster/git.rb
CHANGED
|
@@ -2,8 +2,28 @@ require 'open3'
|
|
|
2
2
|
|
|
3
3
|
module Coaster
|
|
4
4
|
module Git
|
|
5
|
+
def run_cmd(path, command)
|
|
6
|
+
puts "#{path}: #{command}"
|
|
7
|
+
stdout, stderr, status = Open3.capture3(command, chdir: path)
|
|
8
|
+
if status.success?
|
|
9
|
+
puts " ↳ success: #{stdout.split("\n").join("\n ")}"
|
|
10
|
+
stdout
|
|
11
|
+
else
|
|
12
|
+
raise "Error executing command\nPATH: #{path}\nCMD: #{command}\nSTDERR:\n ↳ #{stderr.split("\n").join("\n ")}\nSTDOUT:\n ↳ #{stdout.split("\n").join("\n ")}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
5
15
|
|
|
16
|
+
class << self
|
|
17
|
+
include Coaster::Git
|
|
18
|
+
|
|
19
|
+
def create(path)
|
|
20
|
+
run_cmd(path.split('/')[0..-2].join('/'), "git init #{path}")
|
|
21
|
+
run_cmd(path, "git commit --allow-empty -m 'initial commit'")
|
|
22
|
+
Repository.new(path)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
6
25
|
end
|
|
7
26
|
end
|
|
8
27
|
|
|
28
|
+
require 'coaster/git/options'
|
|
9
29
|
require 'coaster/git/repository'
|
data/lib/coaster/version.rb
CHANGED
data/test/test_git.rb
CHANGED
|
@@ -4,53 +4,5 @@ require 'coaster/git'
|
|
|
4
4
|
|
|
5
5
|
module Coaster
|
|
6
6
|
class TestGit < Minitest::Test
|
|
7
|
-
def setup
|
|
8
|
-
super
|
|
9
|
-
@test_repo_root = File.expand_path('../../tmp/test_repo', __FILE__)
|
|
10
|
-
FileUtils.rm_rf(@test_repo_root)
|
|
11
|
-
FileUtils.mkdir_p(@test_repo_root)
|
|
12
|
-
@beta = Git::Repository.create(File.join(@test_repo_root, 'beta'))
|
|
13
|
-
@beta.run_cmd('echo "hello beta" > README.md')
|
|
14
|
-
@beta.add('.')
|
|
15
|
-
@beta.run_git_cmd('commit -m "hello"')
|
|
16
|
-
@beta.branch('beta_feature')
|
|
17
|
-
@beta.checkout('beta_feature')
|
|
18
|
-
@beta.run_cmd('echo "beta_feature" >> README.md')
|
|
19
|
-
@beta.add('.')
|
|
20
|
-
@beta.run_git_cmd('commit -m "beta_feature"')
|
|
21
|
-
@beta.run_git_cmd('checkout main')
|
|
22
|
-
|
|
23
|
-
@alpha = Git::Repository.create(File.join(@test_repo_root, 'alpha'))
|
|
24
|
-
@alpha.submodule_add!('sb/beta', @beta.path, git_options: {'-c' => {'protocol.file.allow' => 'always'}})
|
|
25
|
-
@alpha.submodule_update!('sb/beta')
|
|
26
|
-
@alpha.run_cmd('echo "hello alpha" > README.md')
|
|
27
|
-
@alpha.add('.')
|
|
28
|
-
@alpha.run_git_cmd('commit -m "hello"')
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def teardown
|
|
32
|
-
FileUtils.rm_rf(@test_repo_root)
|
|
33
|
-
super
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def test_git_deep_merge
|
|
37
|
-
assert_equal "hello alpha\n", @alpha.run_cmd('cat README.md')
|
|
38
|
-
assert_equal "hello beta\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
39
|
-
|
|
40
|
-
@alpha.branch('alpha_feature')
|
|
41
|
-
@alpha.checkout('alpha_feature')
|
|
42
|
-
@alpha.run_cmd('echo "alpha_feature" >> README.md')
|
|
43
|
-
@alpha.submodules['sb/beta'].run_git_cmd('checkout beta_feature')
|
|
44
|
-
@alpha.add('.')
|
|
45
|
-
@alpha.run_git_cmd('commit -m "alpha_feature"')
|
|
46
|
-
assert_equal "README.md\nsb/beta\n", @alpha.run_git_cmd('diff --name-only HEAD~1 HEAD')
|
|
47
|
-
|
|
48
|
-
@alpha.checkout('main')
|
|
49
|
-
@alpha.submodule_update!
|
|
50
|
-
assert_equal "hello beta\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
51
|
-
@alpha.deep_merge('alpha_feature')
|
|
52
|
-
assert_equal "hello alpha\nalpha_feature\n", @alpha.run_cmd('cat README.md')
|
|
53
|
-
assert_equal "hello beta\nbeta_feature\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
54
|
-
end
|
|
55
7
|
end
|
|
56
8
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'minitest/autorun'
|
|
3
|
+
require 'coaster/git'
|
|
4
|
+
|
|
5
|
+
module Coaster
|
|
6
|
+
module Git
|
|
7
|
+
class TestOptions < Minitest::Test
|
|
8
|
+
def test_options_to_s
|
|
9
|
+
# assert_equal '-a b -c d ', Options.new(nil, '-a' => 'b', '-c' => 'd').to_s
|
|
10
|
+
assert_equal '--no-commit ', Options.new(nil, '--no-commit').to_s
|
|
11
|
+
assert_equal '-c a=b', Options.new(nil, '-c' => {'a' => 'b'}).to_s
|
|
12
|
+
assert_equal '-c a=b -c c=d', Options.new(nil, '-c' => {'a' => 'b', 'c' => 'd'}).to_s
|
|
13
|
+
assert_equal '-c a=b -c c=d', Options.new(nil, '-c' => Set[{'a' => 'b'}, {'c' => 'd'}]).to_s
|
|
14
|
+
assert_equal '--config=a=b,c=d', Options.new(nil, '--config' => [Set['a', 'b'], Set['c', 'd']]).to_s
|
|
15
|
+
assert_equal '--config=a=b --config=c=d', Options.new(nil, '--config' => Set[{'a' => 'b'}, {'c' => 'd'}]).to_s
|
|
16
|
+
assert_equal '-c a=b -- aaa bbb', Options.new(nil, '-c' => {'a' => 'b'}, '--' => ['aaa', 'bbb']).to_s
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_options_to_h
|
|
20
|
+
opts = Options.new('git', '-c' => {'b' => 1}, '--config-env' => 'd=1')
|
|
21
|
+
assert_equal({"--config-env"=>{"b"=>"1", "d"=>"1"}}, opts.to_h)
|
|
22
|
+
assert_equal('--config-env=b=1 --config-env=d=1 ', opts.to_s)
|
|
23
|
+
opts = Options.new('merge', '--no-commit')
|
|
24
|
+
assert_equal({"--no-commit" => ''}, opts.to_h)
|
|
25
|
+
assert_equal('--no-commit ', opts.to_s)
|
|
26
|
+
opts = Options.new('git', {'-c' => {'a' => 'b'}, '--' => ['aaa', 'bbb']})
|
|
27
|
+
assert_equal('-c a=b -- aaa bbb', opts.to_s)
|
|
28
|
+
assert_equal({"--config-env" => {"a" => "b"}, '--' => ['aaa', 'bbb']}, opts.to_h)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'minitest/autorun'
|
|
3
|
+
require 'coaster/git'
|
|
4
|
+
|
|
5
|
+
module Coaster
|
|
6
|
+
class TestGitRepository < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
super
|
|
9
|
+
@test_repo_root = File.expand_path('../../tmp/test_repo', __FILE__)
|
|
10
|
+
FileUtils.rm_rf(@test_repo_root)
|
|
11
|
+
FileUtils.mkdir_p(@test_repo_root)
|
|
12
|
+
@beta = Coaster::Git.create(File.join(@test_repo_root, 'beta'))
|
|
13
|
+
@beta.run_cmd('echo "hello beta" > README.md')
|
|
14
|
+
@beta.add('.')
|
|
15
|
+
@beta.run_git_cmd('commit -m "hello"')
|
|
16
|
+
@beta.branch('beta_feature')
|
|
17
|
+
@beta.checkout('beta_feature')
|
|
18
|
+
@beta.run_cmd('echo "beta_feature" >> README.md')
|
|
19
|
+
@beta.add('.')
|
|
20
|
+
@beta.run_git_cmd('commit -m "beta_feature"')
|
|
21
|
+
@beta.run_git_cmd('checkout main')
|
|
22
|
+
|
|
23
|
+
@alpha = Coaster::Git.create(File.join(@test_repo_root, 'alpha'))
|
|
24
|
+
@alpha.with_git_options({'-c' => {'protocol.file.allow' => 'always'}}) do
|
|
25
|
+
@alpha.submodule_add!(@beta.path, 'sb/beta')
|
|
26
|
+
end
|
|
27
|
+
@alpha.submodule_update!('sb/beta')
|
|
28
|
+
@alpha.run_cmd('echo "hello alpha" > README.md')
|
|
29
|
+
@alpha.add('.')
|
|
30
|
+
@alpha.run_git_cmd('commit -m "hello"')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def teardown
|
|
34
|
+
FileUtils.rm_rf(@test_repo_root)
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_git_deep_merge
|
|
39
|
+
assert_equal "hello alpha\n", @alpha.run_cmd('cat README.md')
|
|
40
|
+
assert_equal "hello beta\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
41
|
+
|
|
42
|
+
@alpha.branch('alpha_feature')
|
|
43
|
+
@alpha.checkout('alpha_feature')
|
|
44
|
+
@alpha.run_cmd('echo "alpha_feature" >> README.md')
|
|
45
|
+
@alpha.submodules['sb/beta'].run_git_cmd('checkout beta_feature')
|
|
46
|
+
@alpha.add('.')
|
|
47
|
+
@alpha.run_git_cmd('commit -m "alpha_feature"')
|
|
48
|
+
assert_equal "README.md\nsb/beta\n", @alpha.run_git_cmd('diff --name-only HEAD~1 HEAD')
|
|
49
|
+
|
|
50
|
+
@alpha.checkout('main')
|
|
51
|
+
@alpha.submodule_update!
|
|
52
|
+
@alpha.submodules['sb/beta'].run_cmd('echo "main new commit" >> README2.md')
|
|
53
|
+
@alpha.submodules['sb/beta'].add('.')
|
|
54
|
+
@alpha.submodules['sb/beta'].run_git_cmd('commit -m "main new commit"')
|
|
55
|
+
@alpha.add('.')
|
|
56
|
+
@alpha.run_git_cmd('commit -m "main new commit"')
|
|
57
|
+
assert_equal "hello beta\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
58
|
+
|
|
59
|
+
@alpha.deep_merge('alpha_feature')
|
|
60
|
+
assert_equal "hello alpha\nalpha_feature\n", @alpha.run_cmd('cat README.md')
|
|
61
|
+
assert_equal "hello beta\nbeta_feature\n", @alpha.run_cmd('cat sb/beta/README.md')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: coaster
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.33
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- buzz jung
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-07-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: oj
|
|
@@ -190,6 +190,7 @@ files:
|
|
|
190
190
|
- Rakefile
|
|
191
191
|
- bin/coaster
|
|
192
192
|
- lib/coaster.rb
|
|
193
|
+
- lib/coaster/cmd_options.rb
|
|
193
194
|
- lib/coaster/core_ext.rb
|
|
194
195
|
- lib/coaster/core_ext/array.rb
|
|
195
196
|
- lib/coaster/core_ext/date.rb
|
|
@@ -200,6 +201,7 @@ files:
|
|
|
200
201
|
- lib/coaster/core_ext/standard_error/raven.rb
|
|
201
202
|
- lib/coaster/core_ext/standard_error/sentry.rb
|
|
202
203
|
- lib/coaster/git.rb
|
|
204
|
+
- lib/coaster/git/options.rb
|
|
203
205
|
- lib/coaster/git/repository.rb
|
|
204
206
|
- lib/coaster/rails_ext.rb
|
|
205
207
|
- lib/coaster/rails_ext/backtrace_cleaner.rb
|
|
@@ -212,6 +214,8 @@ files:
|
|
|
212
214
|
- test/support/schema.rb
|
|
213
215
|
- test/test_backtrace.rb
|
|
214
216
|
- test/test_git.rb
|
|
217
|
+
- test/test_git_options.rb
|
|
218
|
+
- test/test_git_repository.rb
|
|
215
219
|
- test/test_helper.rb
|
|
216
220
|
- test/test_month.rb
|
|
217
221
|
- test/test_object_translation.rb
|
|
@@ -249,6 +253,8 @@ test_files:
|
|
|
249
253
|
- test/support/schema.rb
|
|
250
254
|
- test/test_backtrace.rb
|
|
251
255
|
- test/test_git.rb
|
|
256
|
+
- test/test_git_options.rb
|
|
257
|
+
- test/test_git_repository.rb
|
|
252
258
|
- test/test_helper.rb
|
|
253
259
|
- test/test_month.rb
|
|
254
260
|
- test/test_object_translation.rb
|