web_git 0.0.2.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,381 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+
7
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css">
8
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
9
+ <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
11
+ <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
12
+ <style>
13
+ .unchanged {
14
+ display: none !important;
15
+ }
16
+ .commit:hover {
17
+ color: red;
18
+ }
19
+ .heroku {
20
+ background-color: #7952b3;
21
+ }
22
+
23
+ .btn-heroku {
24
+ color: #fff;
25
+ background-color: #7952b3;
26
+ border-color: #7952b3;
27
+ }
28
+
29
+ .btn-heroku:hover {
30
+ color: #fff;
31
+ background-color: #614092;
32
+ border-color: #6d48a4;
33
+ }
34
+ .btn-outline-heroku {
35
+ color: #7952b3;
36
+ border-color: #7952b3;
37
+ background-color: #fff;
38
+ }
39
+ .border-heroku {
40
+ border-color: #7952b3 !important;
41
+ }
42
+ </style>
43
+ <title>Git Client</title>
44
+ </head>
45
+ <body>
46
+ <div class="container mt-3">
47
+ <div class="row">
48
+ <div class="col-md-12">
49
+ <% if @notice.present? %>
50
+ <div class="alert alert-success alert-dismissable" role="alert">
51
+ <%= @notice %>
52
+
53
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
54
+ <span aria-hidden="true">&times;</span>
55
+ </button>
56
+ </div>
57
+ <% elsif @alert.present? %>
58
+
59
+ <div class="alert alert-warning alert-dismissable" role="alert">
60
+ <%= @alert %>
61
+
62
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
63
+ <span aria-hidden="true">&times;</span>
64
+ </button>
65
+ </div>
66
+ <% end %>
67
+ </div>
68
+ </div>
69
+ <ul class="nav nav-tabs nav-fill">
70
+ <li class="nav-item">
71
+ <a class="nav-link active" id="git-tab" href="#git">Git</a>
72
+ </li>
73
+ <li class="nav-item">
74
+ <a class="nav-link" id="heroku-tab" href="#heroku">Heroku</a>
75
+ </li>
76
+ </ul>
77
+
78
+ <div class="tab-content pt-2">
79
+ <div class="tab-pane active" id="git" role="tabpanel" aria-labelledby="profile-tab">
80
+ <div class="row mb-4">
81
+ <div class="col">
82
+ <div class="card">
83
+ <h1 class="card-header">
84
+ <% if !@diff.nil? %>
85
+ On branch <code><%= @current_branch %></code>
86
+ <% else %>
87
+ <code>git status</code>
88
+ <% end %>
89
+ </h1>
90
+
91
+ <div class="card-body">
92
+ <%# if false %>
93
+ <% unless @status.include?("nothing to commit, working tree clean") %>
94
+ <p class="h4 mb-3 text-center">
95
+ You have changes
96
+ </p>
97
+ <% @statuses.each do |status| %>
98
+ <% filelist = status[:file_list].join("\n") %>
99
+ <% if filelist.length > 0 %>
100
+ <%= status[:name] %>
101
+ <pre><%= filelist.strip %></pre>
102
+ <% end %>
103
+ <% end %>
104
+
105
+ <% if !@diff.nil? %>
106
+ <%= @diff %>
107
+ <% end %>
108
+
109
+ <p class="h4 my-3 text-center">
110
+ What do you want to do?
111
+ </p>
112
+
113
+ <div class="row">
114
+ <div class="col">
115
+ <div class="card">
116
+ <div class="card-header h6">
117
+ Commit your changes to the current branch
118
+ </div>
119
+
120
+ <div class="card-body">
121
+ <form action="/git/commit" method="post">
122
+ <div class="form-group">
123
+ <label for="title">Title</label>
124
+ <input class="form-control" type="text" name="title" placeholder="Enter a title for your commit (required)..." required>
125
+ </div>
126
+
127
+ <div class="form-group">
128
+ <label for="description">Description</label>
129
+ <textarea class="form-control" name="description" placeholder="Enter a longer description of your changes (optional)..."></textarea>
130
+ </div>
131
+
132
+ <button class="btn btn-primary btn-block">
133
+ Commit to <%= @current_branch %>
134
+ </button>
135
+ </form>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <div class="col">
141
+ <div class="row mb-2">
142
+ <div class="col">
143
+ <div class="card">
144
+ <div class="card-header h6">
145
+ Switch to a new branch
146
+ </div>
147
+
148
+ <div class="card-body">
149
+ <form action="/git/branch/checkout" class="full-width mb-2" method="post">
150
+ <div class="form-group">
151
+ <label for="branch_name" class="sr-only">Branch name</label>
152
+ <input type="text" name="branch_name" id="branch_name" class="form-control" placeholder="Enter a name for the branch to create..." required>
153
+ </div>
154
+ <button class="btn btn-success btn-block">
155
+ <i class="fas fa-code-branch mr-1"></i>
156
+ Create a new branch
157
+ </button>
158
+ </form>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <div class="row">
165
+ <div class="col">
166
+ <div class="card">
167
+ <div class="card-header h6">
168
+ Discard your changes
169
+ </div>
170
+
171
+ <div class="card-body">
172
+ <a class="btn btn-block btn-danger" href="/git/stash">
173
+ <i class="far fa-trash-alt"></i>
174
+ Discard your changes
175
+ </a>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ <% else %>
184
+
185
+ <div class="row">
186
+ <div class="col">
187
+ <h6 class="card-subtitle mb-2 text-muted">
188
+ <div>
189
+ Remote:
190
+ </div>
191
+ <%= @remotes.first %>
192
+ </h6>
193
+ <pre><%= @status %></pre>
194
+ <%# TODO why is this here? %>
195
+ <% if @current_branch != "master" %>
196
+ <form action="/git/push" method="post">
197
+ <button type="submit" class="btn btn-primary btn-block mb-4" data-html="true" data-toggle="tooltip" data-placement="top" title="<code>git push</code>">
198
+ <i class="fas fa-upload mr-1"></i>
199
+ Push to GitHub
200
+ </button>
201
+ </form>
202
+ <% else %>
203
+ <form action="/git/push" method="post">
204
+ <button type="submit" class="btn btn-primary btn-block mb-4" data-html="true" data-toggle="tooltip" data-placement="top" title="<code>git push -u origin <%= @current_branch %></code>">
205
+ <i class="fas fa-upload mr-1"></i>
206
+ Push to GitHub
207
+ </button>
208
+ </form>
209
+ <% end %>
210
+ <form action="/git/pull" method="post">
211
+ <button type="submit" class="btn btn-primary btn-block mb-4" data-html="true" data-toggle="tooltip" data-placement="top" title="<code>git pull</code>">
212
+ <i class="fas fa-download mr-1"></i>
213
+ Pull from GitHub
214
+ </button>
215
+ </form>
216
+ <p>
217
+ The last thing you did was:
218
+ </p>
219
+
220
+ <blockquote class="blockquote">
221
+ <%= @last_commit_message %>
222
+ </blockquote>
223
+ <a href="#latest_diff_html" class="btn btn-secondary btn-block mb-4" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="latest_diff_html">
224
+ <i class="far fa-eye mr-1"></i>
225
+ Show last commit
226
+ </a>
227
+
228
+ <div id="latest_diff_html" class="collapse">
229
+ <iframe srcdoc="<%= @last_diff_html %>" width="100%" height="400" class="mb-3">
230
+ </iframe>
231
+ </div>
232
+ </div>
233
+
234
+ <div class="col">
235
+ <ul class="list-group">
236
+ <li class="list-group-item list-group-item-success">
237
+ New Branch
238
+ </li>
239
+
240
+ <li class="list-group-item">
241
+ <form action="/git/branch/checkout" method="post">
242
+ <div class="form-group">
243
+ <label for="branch_name">
244
+ Go ahead, experiment!
245
+ </label>
246
+ <input
247
+ id="branch_name" class="form-control" type="text"
248
+ name="branch_name" required
249
+ placeholder="Enter a name for the new branch..."
250
+ >
251
+ </div>
252
+ <button class="btn btn-success btn-block"
253
+ data-html="true" data-toggle="tooltip"
254
+ data-placement="top" title="<code>git checkout -b [BRANCH NAME]</code>"
255
+ >
256
+ <i class="fas fa-code-branch mr-1"></i>
257
+ Create branch
258
+ </button>
259
+ </form>
260
+ </li>
261
+ <li class="list-group-item list-group-item-info">
262
+ Existing branches
263
+ </li>
264
+ <% @branches.each do |branch| %>
265
+ <li class="list-group-item justify-content-between">
266
+ <%= branch %>
267
+ <div class="btn-group">
268
+ <!-- TODO method post, pass branch name-->
269
+ <form action="/git/branch/checkout" method="post">
270
+ <button value="<%= branch %>" name="branch_name" type="submit" class="btn btn-primary btn-sm" data-html="true" data-toggle="tooltip" data-placement="top" title="<code>git checkout <%= branch %></code>">
271
+ <i class="fas fa-exchange-alt"></i>
272
+ </button>
273
+ </form>
274
+ <form action="/git/branch/delete" method="post">
275
+ <button type="submit" value="<%= branch %>" name="branch_name" class="btn btn-warning btn-sm" data-html="true" data-toggle="tooltip" data-placement="top" title="<code>git branch -d <%= branch %></code>">
276
+ <i class="far fa-trash-alt"></i>
277
+ </button>
278
+ </form>
279
+ </div>
280
+ </li>
281
+ <% end %>
282
+ </ul>
283
+ </div>
284
+ </div>
285
+ <% end %>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <div class="row mb-4">
292
+ <div class="col">
293
+ <div class="card">
294
+ <h2 class="card-header">
295
+ History
296
+ </h2>
297
+
298
+ <div class="card-body">
299
+ <p class="lead">Do you want to jump back in time and go down a different path?</p>
300
+ <form action="/git/branch/checkout/new" method="post">
301
+ <div class="form-group">
302
+ <label for="commit_hash">Branch off of</label>
303
+ <input type="text" class="form-control" name="commit_hash"
304
+ id="commit_hash" required
305
+ placeholder="Enter the sequence of digits preceding the commit (it's &quot;hash&quot;) that you want to branch off of...">
306
+ </div>
307
+
308
+ <div class="form-group">
309
+ <label for="branch_name">Branch name</label>
310
+ <input type="text" class="form-control" name="branch_name"
311
+ id="branch_name" placeholder="Enter a name for the new branch..."
312
+ required >
313
+ </div>
314
+
315
+ <% if @changed_files.count > 0 %>
316
+ <button disabled="disabled" class="btn btn-primary btn-block">
317
+ Can't go back in time while you have pending changes. Commit or discard them first.
318
+ </button>
319
+ <% else %>
320
+ <!-- TODO use JS to replace -->
321
+ <button class="btn btn-success btn-block" data-toggle="tooltip" data-html="true" data-placement="top" title="<code>git checkout [OLD HASH]; git checkout -b [NEW BRANCH NAME]</code>">
322
+ Create a new branch off of previous commit
323
+ </button>
324
+ <% end%>
325
+ </form>
326
+ </div>
327
+ <pre class="bg-dark text-white p-3"><%= @cli_graph_interactive %></pre>
328
+ </div>
329
+ </div>
330
+ </div>
331
+ </div>
332
+ <div class="tab-pane" id="heroku" role="tabpanel" aria-labelledby="home-tab">
333
+ <ul class="list-group">
334
+ <li class="list-group-item heroku text-white d-flex justify-content-between">
335
+ <% if @heroku_auth.empty? %>
336
+ <span>Log in</span>
337
+ <% else %>
338
+ <span>Logged in as:</span>
339
+ <span><%= @heroku_auth %></span>
340
+ <% end %>
341
+ </li>
342
+ <% if @heroku_auth.empty? %>
343
+ <div class="border border-heroku p-4">
344
+ <form action="/git/heroku/login" method="post">
345
+ <div class="form-group">
346
+ <label for="heroku_email">Email address</label>
347
+ <input type="email" class="form-control" name="heroku_email" id="heroku_email" aria-describedby="emailHelp">
348
+ </div>
349
+ <div class="form-group">
350
+ <label for="heroku_password">Password</label>
351
+ <input type="password" class="form-control" name="heroku_password" id="heroku_password">
352
+ </div>
353
+ <button type="submit" data-html="true" data-toggle="tooltip"
354
+ data-placement="top" title="<code>heroku login -i</code>" class="btn btn-heroku btn-block">Log in</button>
355
+ </form>
356
+ </div>
357
+
358
+ <% end %>
359
+ </ul>
360
+ </div>
361
+ </div>
362
+ </div>
363
+ <script>
364
+
365
+ $(document).ready(function() {
366
+ $(".sha").click(function() {
367
+ var text = this.textContent
368
+ $("#commit_hash").val(text);
369
+ });
370
+ $(function () {
371
+ $('[data-toggle="tooltip"]').tooltip()
372
+ })
373
+ $('.nav-tabs a').on('click', function (event) {
374
+ event.preventDefault()
375
+ $(this).tab('show')
376
+ })
377
+ });
378
+
379
+ </script>
380
+ </body>
381
+ </html>
@@ -0,0 +1,234 @@
1
+
2
+ require "diffy"
3
+ require "git"
4
+ class Diff
5
+
6
+ def self.get_diff
7
+ # Dir.chdir(Rails.root) do
8
+ `git diff`
9
+ # end
10
+ end
11
+
12
+ def self.get_each_left(diff)
13
+ filenames = get_file_names("")
14
+ files = file_diffs(diff)
15
+ lefts = {}
16
+ files.each_with_index do |file, i|
17
+ file_content = ""
18
+ lines = file.split("\n").drop(4)
19
+ start_line = 0
20
+ current_line_index = 0
21
+ line_number = start_line + current_line_index
22
+ lines.each do |line|
23
+ if !line.match?(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/)
24
+ if line[0] != "+"
25
+ file_content += "#{line_number}| " + line + "\n"
26
+ line_number += 1
27
+ end
28
+ else
29
+ current_line_index = 0
30
+ # The line numbers in the output of a git diff match this regex
31
+ numbers = line.scan(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/).map(&:join)
32
+ # If left, starting line number is the first one in a split Array
33
+ start_line = numbers[0].split(" ")[0].
34
+ split(",")[0].to_i.abs
35
+ line_number = start_line + current_line_index
36
+ file_content += "\n"
37
+ end
38
+ end
39
+ lefts[filenames[i]] = file_content.chomp "\n"
40
+ end
41
+ lefts
42
+ end
43
+
44
+ def self.get_each_right(diff)
45
+ filenames = get_file_names("")
46
+ files = file_diffs(diff)
47
+ rights = {}
48
+ files.each_with_index do |file, i|
49
+ file_content = ""
50
+ lines = file.split("\n").drop(4)
51
+ start_line = 0
52
+ current_line_index = 0
53
+ line_number = start_line + current_line_index
54
+ lines.each do |line|
55
+ # The line numbers in the output of a git diff match this regex
56
+ # @@ -61,18 +61,15 @@
57
+ if !line.match?(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/)
58
+ if line[0] != "-"
59
+ file_content += "#{line_number}| " + line + "\n"
60
+ line_number += 1
61
+ end
62
+ else
63
+ current_line_index = 0
64
+ numbers = line.scan(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/).map(&:join)
65
+ # If right, start line is the second in a split Array
66
+ start_line = numbers[0].split(" ")[1].
67
+ split(",")[0].to_i.abs
68
+ line_number = start_line + current_line_index
69
+ file_content += "\n"
70
+ end
71
+ end
72
+ rights[filenames[i]] = file_content.chomp "\n"
73
+ end
74
+ rights
75
+ end
76
+
77
+ def self.get_last_commit_hash
78
+ working_dir = Dir.pwd
79
+ git = Git.open(working_dir)
80
+ git.log.first.sha.slice(0, 7)
81
+ end
82
+
83
+ def self.file_diffs(diff)
84
+ diff.scan(/diff --git.*?(?=diff --git|\z)/m)
85
+ end
86
+
87
+ def self.match_other_files(line, file, filenames)
88
+ filenames.each do |other_file|
89
+ if file != other_file
90
+ # It looks like:
91
+ # --- a/<path-to-file>
92
+ # +++ b/<path-to-file>
93
+ if line.include?('diff --git a/' + other_file + ' b/' + other_file)
94
+ return true
95
+ end
96
+ end
97
+ end
98
+ false
99
+ end
100
+
101
+ def self.get_file_names(commit)
102
+ git = Git.open(Dir.pwd)
103
+ if commit.empty?
104
+ filenames = git.status.changed.keys
105
+ else
106
+ filenames = git.diff(commit, "HEAD").map(&:path)
107
+ end
108
+ filenames
109
+ end
110
+
111
+ def self.get_last_diff
112
+ # Dir.chdir(Rails.root) do
113
+ `git diff -M HEAD~1`
114
+ # end
115
+ end
116
+
117
+ def self.get_last_left(diff)
118
+ filenames = get_file_names("HEAD~1")
119
+ files = file_diffs(diff)
120
+ ones = {}
121
+ files.each_with_index do |file, i|
122
+ file_content = ""
123
+ lines = file.split("\n").drop(4)
124
+ lines.each do |line|
125
+ # The line numbers in the output of a git diff match this regex
126
+ # @@ -61,18 +61,15 @@
127
+ if !line.match?(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/)
128
+ if line[0] != "+"
129
+ line.slice!(0)
130
+ file_content += line + "\n"
131
+ end
132
+ else
133
+ file_content += "\n"
134
+ end
135
+ end
136
+ ones[filenames[i]] = file_content.chomp "\n"
137
+ end
138
+ ones
139
+ end
140
+
141
+ def self.get_last_right(diff)
142
+ filenames = get_file_names("HEAD~1")
143
+ files = file_diffs(diff)
144
+ ones = {}
145
+ files.each_with_index do |file, i|
146
+ file_content = ""
147
+ lines = file.split("\n").drop(4)
148
+ lines.each do |line|
149
+ if !line.match?(/@@ ([-]\d+,\d+\s[+]\d+,\d+) @@/)
150
+ if line[0] != "+"
151
+ elsif line[0] == "+"
152
+ line.slice!(0)
153
+ file_content += line + "\n"
154
+ end
155
+ else
156
+ file_content += "\n"
157
+ end
158
+ end
159
+ ones[filenames[i]] = file_content.chomp "\n"
160
+ end
161
+ ones
162
+ end
163
+
164
+ def self.last_to_html(diff)
165
+ left_hash = get_last_left(diff)
166
+ right_hash = get_last_right(diff)
167
+
168
+ html_output = '<link rel="stylesheet"' +
169
+ 'href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/' +
170
+ 'bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/' +
171
+ '1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">'
172
+ html_output += '<style>'
173
+ html_output += Diffy::CSS
174
+ html_output += '</style>'
175
+ html_output += '<div class="card" style="overflow-y: scroll;max-height:400px">'
176
+ left_hash.keys.each do |file|
177
+ html_output += '<div class="file mb-4 p-1">'
178
+ html_output += '<h4>' + file + '</h4>'
179
+ html_output += Diffy::Diff.new(
180
+ left_hash[file],
181
+ right_hash[file],
182
+ :include_plus_and_minus_in_html => true,
183
+ :allow_empty_diff => false
184
+ ).to_s(:html)
185
+ html_output += '</div>'
186
+ end
187
+ html_output += '</div>'
188
+ html_output
189
+ end
190
+
191
+ def self.diff_to_html(diff)
192
+ left_hash = get_each_left(diff)
193
+ right_hash = get_each_right(diff)
194
+ html_output = '<div style="overflow-y: scroll;height:400px">'
195
+ html_output += '<style>'
196
+ html_output += Diffy::CSS
197
+ html_output += '</style>'
198
+ html_output += '<div class="row mb-3">'
199
+ html_output += '<div class="col-md-12 offset" style="overflow-y: scroll;">'
200
+
201
+ left_hash.keys.each do |file|
202
+ html_output += '<div class="row text-center">
203
+ <div class="col-12">
204
+ <h4>'
205
+ html_output+= file.to_s
206
+ html_output += '</h4>
207
+ </div>
208
+ </div>
209
+ <div class="row mb-4">
210
+ <div class="col-6">'
211
+ html_output += Diffy::SplitDiff.new(
212
+ left_hash[file],
213
+ right_hash[file],
214
+ :format => :html
215
+ ).left
216
+
217
+ html_output +=
218
+ '</div>
219
+ <div class="col-6">'
220
+ html_output += Diffy::SplitDiff.new(
221
+ left_hash[file],
222
+ right_hash[file],
223
+ :format => :html
224
+ ).right
225
+
226
+ html_output += '</div></div>'
227
+ end
228
+ html_output += "</div>"
229
+ html_output += "</div>"
230
+ html_output += "</div>"
231
+ html_output
232
+
233
+ end
234
+ end
@@ -0,0 +1,3 @@
1
+ module WebGit
2
+ class AuthenticationError < StandardError; end
3
+ end