1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
# frozen_string_literal: true
require 'cgi'
require 'uri'
require 'open3'
require 'fileutils'
require 'tmpdir'
module QA
module Git
class Repository
include Scenario::Actable
attr_writer :password
attr_accessor :env_vars
def initialize
# We set HOME to the current working directory (which is a
# temporary directory created in .perform()) so the temporarily dropped
# .netrc can be utilised
self.env_vars = [%Q{HOME="#{File.dirname(netrc_file_path)}"}]
end
def self.perform(*args)
Dir.mktmpdir do |dir|
Dir.chdir(dir) { super }
end
end
def uri=(address)
@uri = URI(address)
end
def username=(username)
@username = username
@uri.user = username
end
def use_default_credentials
self.username, self.password = default_credentials
add_credentials_to_netrc unless ssh_key_set?
end
def clone(opts = '')
run("git clone #{opts} #{uri} ./")
end
def checkout(branch_name)
run(%Q{git checkout "#{branch_name}"})
end
def checkout_new_branch(branch_name)
run(%Q{git checkout -b "#{branch_name}"})
end
def shallow_clone
clone('--depth 1')
end
def configure_identity(name, email)
run(%Q{git config user.name #{name}})
run(%Q{git config user.email #{email}})
add_credentials_to_netrc
end
def commit_file(name, contents, message)
add_file(name, contents)
commit(message)
end
def add_file(name, contents)
::File.write(name, contents)
run(%Q{git add #{name}})
end
def commit(message)
run(%Q{git commit -m "#{message}"})
end
def push_changes(branch = 'master')
run("git push #{uri} #{branch}")
end
def commits
run('git log --oneline').split("\n")
end
def use_ssh_key(key)
@private_key_file = Tempfile.new("id_#{SecureRandom.hex(8)}")
File.binwrite(private_key_file, key.private_key)
File.chmod(0700, private_key_file)
@known_hosts_file = Tempfile.new("known_hosts_#{SecureRandom.hex(8)}")
keyscan_params = ['-H']
keyscan_params << "-p #{uri.port}" if uri.port
keyscan_params << uri.host
run("ssh-keyscan #{keyscan_params.join(' ')} >> #{known_hosts_file.path}")
self.env_vars << %Q{GIT_SSH_COMMAND="ssh -i #{private_key_file.path} -o UserKnownHostsFile=#{known_hosts_file.path}"}
end
def delete_ssh_key
return unless ssh_key_set?
private_key_file.close(true)
known_hosts_file.close(true)
end
private
attr_reader :uri, :username, :password, :known_hosts_file, :private_key_file
def ssh_key_set?
!private_key_file.nil?
end
def run(command_str)
command = [env_vars, command_str, '2>&1'].compact.join(' ')
Runtime::Logger.debug "Git: command=[#{command}]"
output, _ = Open3.capture2(command)
output = output.chomp.gsub(/\s+$/, '')
Runtime::Logger.debug "Git: output=[#{output}]"
output
end
def default_credentials
if ::QA::Runtime::User.ldap_user?
[Runtime::User.ldap_username, Runtime::User.ldap_password]
else
[Runtime::User.username, Runtime::User.password]
end
end
def tmp_netrc_directory
@tmp_netrc_directory ||= File.join(Dir.tmpdir, "qa-netrc-credentials", $$.to_s)
end
def netrc_file_path
@netrc_file_path ||= File.join(tmp_netrc_directory, '.netrc')
end
def netrc_content
"machine #{uri.host} login #{username} password #{password}"
end
def netrc_already_contains_content?
File.exist?(netrc_file_path) &&
File.readlines(netrc_file_path).grep(/^#{netrc_content}$/).any?
end
def add_credentials_to_netrc
# Despite libcurl supporting a custom .netrc location through the
# CURLOPT_NETRC_FILE environment variable, git does not support it :(
# Info: https://curl.haxx.se/libcurl/c/CURLOPT_NETRC_FILE.html
#
# This will create a .netrc in the correct working directory, which is
# a temporary directory created in .perform()
#
return if netrc_already_contains_content?
FileUtils.mkdir_p(tmp_netrc_directory)
File.open(netrc_file_path, 'a') { |file| file.puts(netrc_content) }
File.chmod(0600, netrc_file_path)
end
end
end
end
|