1
|
diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb
|
2
|
index d41977d..14f1dc6 100644
|
3
|
--- a/app/helpers/repositories_helper.rb
|
4
|
+++ b/app/helpers/repositories_helper.rb
|
5
|
@@ -164,7 +164,11 @@ module RepositoriesHelper
|
6
|
end
|
7
|
|
8
|
def git_field_tags(form, repository)
|
9
|
- content_tag('p', form.text_field(:url, :label => 'Path to .git directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
10
|
+ if Setting.serve_git_repositories? and (repository == nil or repository.url.blank?)
|
11
|
+ content_tag('p', form.text_field(:url, :value => GitManager.repositories_root + '/' + repository.project.identifier + '.git'), :label => 'Path to .git directory', :size => 60, :required => true)
|
12
|
+ else
|
13
|
+ content_tag('p', form.text_field(:url, :label => 'Path to .git directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
14
|
+ end
|
15
|
end
|
16
|
|
17
|
def cvs_field_tags(form, repository)
|
18
|
diff --git a/app/models/authorized_keys_entry.rb b/app/models/authorized_keys_entry.rb
|
19
|
new file mode 100644
|
20
|
index 0000000..3f9f4b8
|
21
|
--- /dev/null
|
22
|
+++ b/app/models/authorized_keys_entry.rb
|
23
|
@@ -0,0 +1,190 @@
|
24
|
+require "strscan"
|
25
|
+require 'thread'
|
26
|
+
|
27
|
+class AuthorizedKeysEntry
|
28
|
+ COMMENT=/^#/
|
29
|
+ BLANK=/^\s+$/
|
30
|
+ AUTHORIZED_KEYS_PARSER=/^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+)(?: (.+))?$/
|
31
|
+ KEY_TYPES=['ssh-dss','ssh-rsa']
|
32
|
+ KEY_FORMAT=/\A[\w\/\+\=]+\z/
|
33
|
+ IDENTIFIER_FORMAT=/\A[\w@\.\-]+\z/
|
34
|
+ @@authorized_keys_filename="~/.ssh/authorized_keys"
|
35
|
+
|
36
|
+ attr_reader :identifier, :key, :type
|
37
|
+ attr_accessor :options
|
38
|
+
|
39
|
+ @authorized_keys_lock = Mutex.new
|
40
|
+
|
41
|
+ # Create object from string from authorized_keys
|
42
|
+ def initialize(authorized_keys_string = nil)
|
43
|
+ @key = ''
|
44
|
+ @options = []
|
45
|
+ create_from_authorized_keys(authorized_keys_string) if authorized_keys_string != nil
|
46
|
+ end
|
47
|
+
|
48
|
+ def identifier=(identifier)
|
49
|
+ @identifier = identifier
|
50
|
+ @validated = false
|
51
|
+ end
|
52
|
+
|
53
|
+ def key=(key)
|
54
|
+ @key = key
|
55
|
+ @validated = false
|
56
|
+ end
|
57
|
+
|
58
|
+ def type=(type)
|
59
|
+ @type = type
|
60
|
+ @validated = false
|
61
|
+ end
|
62
|
+
|
63
|
+ def save
|
64
|
+ raise "Invalid key format" if !validate
|
65
|
+ AuthorizedKeysEntry.save_entry(self)
|
66
|
+ end
|
67
|
+
|
68
|
+ def self.find_by_identifier(identifier)
|
69
|
+ read_entries do |entry|
|
70
|
+ return entry if entry.identifier == identifier
|
71
|
+ end
|
72
|
+ return nil
|
73
|
+ end
|
74
|
+
|
75
|
+ def validate
|
76
|
+ return true if @key == ""
|
77
|
+ return false if !@options.kind_of?(Array)
|
78
|
+ return true if @validated
|
79
|
+ # Clean key from any garbage user might have entered while copying the key
|
80
|
+ @key = @key.gsub(/\A(ssh-dss|ssh-rsa)\s/,"").gsub(/\s\w+@[\.\w\-\n]+\s*\Z/,"").gsub(/\s/,'')
|
81
|
+ return false if (@key=~KEY_FORMAT) == nil or !KEY_TYPES.include?(@type)
|
82
|
+ return false if (@identifier=~IDENTIFIER_FORMAT) == nil
|
83
|
+
|
84
|
+ Tempfile.open("redmine") do |file|
|
85
|
+ file << get_id_dsa_pub_format
|
86
|
+ file.close
|
87
|
+ @validated = system "ssh-keygen -B -f #{file.path()} &> /dev/null"
|
88
|
+ end
|
89
|
+ return @validated
|
90
|
+ end
|
91
|
+
|
92
|
+ def to_s
|
93
|
+ get_authorized_keys_format
|
94
|
+ end
|
95
|
+
|
96
|
+ def self.authorized_keys_filename=(filename)
|
97
|
+ @@authorized_keys_filename = filename
|
98
|
+ end
|
99
|
+
|
100
|
+ private
|
101
|
+
|
102
|
+ def create_from_authorized_keys(line)
|
103
|
+ m = AUTHORIZED_KEYS_PARSER.match(line)
|
104
|
+ raise ArgumentError, "Invalid format of authorized_keys entry" if m == nil
|
105
|
+
|
106
|
+ @options, @type, @key, @identifier = m[1], m[2], m[3], m[4]
|
107
|
+ @options = AuthorizedKeysEntry.parse_options(@options)
|
108
|
+ end
|
109
|
+
|
110
|
+ def get_authorized_keys_format
|
111
|
+ raise ArgumentError, 'Entry must have the type set' if @type == nil
|
112
|
+ s = ""
|
113
|
+ s += @options.join(",") + " " if !@options.empty?
|
114
|
+ s += @type + " " + @key
|
115
|
+ s += " " + @identifier if @identifier
|
116
|
+ return s
|
117
|
+ end
|
118
|
+
|
119
|
+ def get_id_dsa_pub_format
|
120
|
+ raise ArgumentError, 'Entry must have the type set' if @type == nil
|
121
|
+ s = ""
|
122
|
+ s += @type + " " + @key
|
123
|
+ s += " " + @identifier if @identifier
|
124
|
+ return s
|
125
|
+ end
|
126
|
+
|
127
|
+ def self.parse_options(options)
|
128
|
+ result = []
|
129
|
+ return result if options == nil
|
130
|
+ scanner = StringScanner.new(options)
|
131
|
+ while !scanner.eos?
|
132
|
+ scanner.skip(/[ \t]*/)
|
133
|
+ # scan a long option
|
134
|
+ if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
|
135
|
+ result << out
|
136
|
+ else
|
137
|
+ # found an unscannable token, let's abort
|
138
|
+ break
|
139
|
+ end
|
140
|
+ # eat a comma
|
141
|
+ scanner.skip(/[\t]*,[\t]*/)
|
142
|
+ end
|
143
|
+ return result
|
144
|
+ end
|
145
|
+
|
146
|
+ def self.read_entries
|
147
|
+ filename = File.expand_path(@@authorized_keys_filename)
|
148
|
+ return if !File.exists?(filename)
|
149
|
+
|
150
|
+ File.open(filename) do |file|
|
151
|
+ file.flock(File::LOCK_SH)
|
152
|
+ begin
|
153
|
+ file.each_line do |line|
|
154
|
+ next if COMMENT.match(line) or BLANK.match(line)
|
155
|
+ yield AuthorizedKeysEntry.new(line)
|
156
|
+ end
|
157
|
+ ensure
|
158
|
+ file.flock(File::LOCK_UN)
|
159
|
+ end
|
160
|
+ end
|
161
|
+ end
|
162
|
+
|
163
|
+ def self.save_entry(entry)
|
164
|
+ filename = File.expand_path(@@authorized_keys_filename)
|
165
|
+
|
166
|
+ FileUtils.mkdir_p(File.dirname(filename))
|
167
|
+
|
168
|
+ found = false
|
169
|
+ entries = []
|
170
|
+ file = nil
|
171
|
+ begin
|
172
|
+ if File.exist?(filename)
|
173
|
+ file = File.open(filename, "r")
|
174
|
+ # TODO: somehow handle flock blocking
|
175
|
+ file.flock(File::LOCK_EX)
|
176
|
+ file.each_line do |line|
|
177
|
+ next if COMMENT.match(line) or BLANK.match(line)
|
178
|
+ entries << AuthorizedKeysEntry.new(line)
|
179
|
+ end
|
180
|
+
|
181
|
+ entries.each do |e|
|
182
|
+ if entry.identifier == e.identifier
|
183
|
+ return if entry.key == e.key and entry.type == e.type
|
184
|
+
|
185
|
+ found = true
|
186
|
+ if entry.key != ""
|
187
|
+ e.key = entry.key
|
188
|
+ e.type = entry.type
|
189
|
+ e.options = entry.options
|
190
|
+ else
|
191
|
+ entries.delete(e)
|
192
|
+ end
|
193
|
+ break
|
194
|
+ end
|
195
|
+ end
|
196
|
+ end
|
197
|
+
|
198
|
+ if !found and entry.key != ""
|
199
|
+ entries << entry
|
200
|
+ end
|
201
|
+
|
202
|
+ File.open(filename, "w") do |write_file|
|
203
|
+ write_file.flock(File::LOCK_EX) if file == nil
|
204
|
+ entries.each do |entry|
|
205
|
+ write_file << entry.to_s + "\n"
|
206
|
+ end
|
207
|
+ end
|
208
|
+ ensure
|
209
|
+ file.close if file != nil
|
210
|
+ end
|
211
|
+ end
|
212
|
+end
|
213
|
+
|
214
|
diff --git a/app/models/changeset.rb b/app/models/changeset.rb
|
215
|
index 759d240..744fc2c 100644
|
216
|
--- a/app/models/changeset.rb
|
217
|
+++ b/app/models/changeset.rb
|
218
|
@@ -70,56 +70,74 @@ class Changeset < ActiveRecord::Base
|
219
|
scan_comment_for_issue_ids
|
220
|
end
|
221
|
require 'pp'
|
222
|
-
|
223
|
- def scan_comment_for_issue_ids
|
224
|
- return if comments.blank?
|
225
|
+
|
226
|
+ # returns issue ids found in message
|
227
|
+ # three arrays are returned, references issues, fixed ones and wrong numbers (not Issues)
|
228
|
+ def self.find_issue_ids(message, project)
|
229
|
+ return [[],[]] if message.blank?
|
230
|
# keywords used to reference issues
|
231
|
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
|
232
|
# keywords used to fix issues
|
233
|
fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
|
234
|
- # status and optional done ratio applied
|
235
|
- fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
|
236
|
- done_ratio = Setting.commit_fix_done_ratio.blank? ? nil : Setting.commit_fix_done_ratio.to_i
|
237
|
|
238
|
kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
|
239
|
- return if kw_regexp.blank?
|
240
|
+ return [[],[]] if kw_regexp.blank?
|
241
|
|
242
|
referenced_issues = []
|
243
|
+ fixed_issues = []
|
244
|
+ wrong_issue_ids = []
|
245
|
|
246
|
if ref_keywords.delete('*')
|
247
|
# find any issue ID in the comments
|
248
|
target_issue_ids = []
|
249
|
- comments.scan(%r{([\s\(,-]|^)#(\d+)(?=[[:punct:]]|\s|<|$)}).each { |m| target_issue_ids << m[1] }
|
250
|
- referenced_issues += repository.project.issues.find_all_by_id(target_issue_ids)
|
251
|
+ message.scan(%r{([\s\(,-]|^)#(\d+)(?=[[:punct:]]|\s|<|$)}).each { |m| target_issue_ids << m[1] }
|
252
|
+ found_issues = project.issues.find_all_by_id(target_issue_ids)
|
253
|
+ referenced_issues += found_issues
|
254
|
+ found_issues.each { |issue| target_issue_ids.delete(issue.id.to_s) }
|
255
|
+ wrong_issue_ids += target_issue_ids
|
256
|
end
|
257
|
|
258
|
- comments.scan(Regexp.new("(#{kw_regexp})[\s:]+(([\s,;&]*#?\\d+)+)", Regexp::IGNORECASE)).each do |match|
|
259
|
+ message.scan(Regexp.new("(#{kw_regexp})[\s:]+(([\s,;&]*#?\\d+)+)", Regexp::IGNORECASE)).each do |match|
|
260
|
action = match[0]
|
261
|
target_issue_ids = match[1].scan(/\d+/)
|
262
|
- target_issues = repository.project.issues.find_all_by_id(target_issue_ids)
|
263
|
- if fix_status && fix_keywords.include?(action.downcase)
|
264
|
- # update status of issues
|
265
|
- logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
|
266
|
- target_issues.each do |issue|
|
267
|
- # the issue may have been updated by the closure of another one (eg. duplicate)
|
268
|
- issue.reload
|
269
|
- # don't change the status is the issue is closed
|
270
|
- next if issue.status.is_closed?
|
271
|
- csettext = "r#{self.revision}"
|
272
|
- if self.scmid && (! (csettext =~ /^r[0-9]+$/))
|
273
|
- csettext = "commit:\"#{self.scmid}\""
|
274
|
- end
|
275
|
- journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext))
|
276
|
- issue.status = fix_status
|
277
|
- issue.done_ratio = done_ratio if done_ratio
|
278
|
- issue.save
|
279
|
- Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
280
|
- end
|
281
|
+ target_issues = project.issues.find_all_by_id(target_issue_ids)
|
282
|
+ target_issues.each { |issue| target_issue_ids.delete(issue.id.to_s) }
|
283
|
+ wrong_issue_ids += target_issue_ids
|
284
|
+ if fix_keywords.include?(action.downcase)
|
285
|
+ fixed_issues += target_issues
|
286
|
+ else
|
287
|
+ referenced_issues += target_issues
|
288
|
end
|
289
|
- referenced_issues += target_issues
|
290
|
end
|
291
|
-
|
292
|
- self.issues = referenced_issues.uniq
|
293
|
+ return [referenced_issues.uniq, fixed_issues.uniq, wrong_issue_ids.uniq]
|
294
|
+ end
|
295
|
+
|
296
|
+ def scan_comment_for_issue_ids
|
297
|
+ return if comments.blank?
|
298
|
+ # status and optional done ratio applied
|
299
|
+ fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
|
300
|
+ done_ratio = Setting.commit_fix_done_ratio.blank? ? nil : Setting.commit_fix_done_ratio.to_i
|
301
|
+
|
302
|
+ referenced_issues, fixed_issues, wrong_issues = Changeset.find_issue_ids(comments, repository.project)
|
303
|
+
|
304
|
+ # update status of issues
|
305
|
+ logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
|
306
|
+ fixed_issues.each do |issue|
|
307
|
+ # the issue may have been updated by the closure of another one (eg. duplicate)
|
308
|
+ issue.reload
|
309
|
+ # don't change the status is the issue is closed
|
310
|
+ next if issue.status.is_closed?
|
311
|
+ csettext = "r#{self.revision}"
|
312
|
+ if self.scmid && (! (csettext =~ /^r[0-9]+$/))
|
313
|
+ csettext = "commit:\"#{self.scmid}\""
|
314
|
+ end
|
315
|
+ journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext))
|
316
|
+ issue.status = fix_status
|
317
|
+ issue.done_ratio = done_ratio if done_ratio
|
318
|
+ issue.save
|
319
|
+ Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
320
|
+ end
|
321
|
+ self.issues = (referenced_issues + fixed_issues).uniq
|
322
|
end
|
323
|
|
324
|
# Returns the previous changeset
|
325
|
diff --git a/app/models/git_checks/committer.rb b/app/models/git_checks/committer.rb
|
326
|
new file mode 100644
|
327
|
index 0000000..40cea0b
|
328
|
--- /dev/null
|
329
|
+++ b/app/models/git_checks/committer.rb
|
330
|
@@ -0,0 +1,14 @@
|
331
|
+class GitChecks::Committer < GitManager::CommitCheck
|
332
|
+ def self.check(revision, branch, user, role, project, git)
|
333
|
+ # Check: committer name and email
|
334
|
+ if revision.author != "#{user.name} <#{user.mail}>"
|
335
|
+ return [ "Commit author name or email is wrong",
|
336
|
+ " Execute following commands and _recreate_ commit:",
|
337
|
+ " git config --global user.name \"#{user.name}\"",
|
338
|
+ " git config --global user.email #{user.mail}",
|
339
|
+ ]
|
340
|
+ end
|
341
|
+ return []
|
342
|
+ end
|
343
|
+end
|
344
|
+
|
345
|
diff --git a/app/models/git_checks/delete_branch.rb b/app/models/git_checks/delete_branch.rb
|
346
|
new file mode 100644
|
347
|
index 0000000..94a96eb
|
348
|
--- /dev/null
|
349
|
+++ b/app/models/git_checks/delete_branch.rb
|
350
|
@@ -0,0 +1,9 @@
|
351
|
+class GitChecks::DeleteBranch < GitManager::RefCheck
|
352
|
+ def self.check(old_rev, new_rev, new_rev_type, branch, user, role, project, git)
|
353
|
+ if new_rev_type == "delete"
|
354
|
+ return "Deleting branch can be done only by repository manager"
|
355
|
+ end
|
356
|
+ return []
|
357
|
+ end
|
358
|
+end
|
359
|
+
|
360
|
diff --git a/app/models/git_checks/fast_forward.rb b/app/models/git_checks/fast_forward.rb
|
361
|
new file mode 100644
|
362
|
index 0000000..03b74c5
|
363
|
--- /dev/null
|
364
|
+++ b/app/models/git_checks/fast_forward.rb
|
365
|
@@ -0,0 +1,10 @@
|
366
|
+class GitChecks::FastForward < GitManager::RefCheck
|
367
|
+ def self.check(old_rev, new_rev, new_rev_type, branch, user, role, project, git)
|
368
|
+ # Check: fast forward
|
369
|
+ if old_rev != git.class::EMPTY_COMMIT and git.merge_base(old_rev, new_rev) != old_rev
|
370
|
+ return "Only fast-forward commits are allowed"
|
371
|
+ end
|
372
|
+ return []
|
373
|
+ end
|
374
|
+end
|
375
|
+
|
376
|
diff --git a/app/models/git_checks/initial_commit.rb b/app/models/git_checks/initial_commit.rb
|
377
|
new file mode 100644
|
378
|
index 0000000..c08344e
|
379
|
--- /dev/null
|
380
|
+++ b/app/models/git_checks/initial_commit.rb
|
381
|
@@ -0,0 +1,9 @@
|
382
|
+class GitChecks::InitialCommit < GitManager::RefCheck
|
383
|
+ def self.check(old_rev, new_rev, new_rev_type, branch, user, role, project, git)
|
384
|
+ if old_rev == git.class::EMPTY_COMMIT and !role.allowed_to?(:manage_repository)
|
385
|
+ return "Initial commit can be done only by repository manager"
|
386
|
+ end
|
387
|
+ return []
|
388
|
+ end
|
389
|
+end
|
390
|
+
|
391
|
diff --git a/app/models/git_checks/issue.rb b/app/models/git_checks/issue.rb
|
392
|
new file mode 100644
|
393
|
index 0000000..99b11a8
|
394
|
--- /dev/null
|
395
|
+++ b/app/models/git_checks/issue.rb
|
396
|
@@ -0,0 +1,29 @@
|
397
|
+class GitChecks::Issue < GitManager::CommitCheck
|
398
|
+ def self.check(revision, branch, user, role, project, git)
|
399
|
+ referenced_issues, fixes_issues, wrong_issues = Changeset.find_issue_ids(revision.message, project)
|
400
|
+ issues = referenced_issues + fixes_issues
|
401
|
+
|
402
|
+ errors = []
|
403
|
+
|
404
|
+ if !wrong_issues.empty?
|
405
|
+ errors << "Some issue numbers are wrong: #{wrong_issues.join(',')}"
|
406
|
+ end
|
407
|
+
|
408
|
+ issues.each do |issue_number|
|
409
|
+ issue = Issue.find(issue_number)
|
410
|
+ if issue.closed?
|
411
|
+ errors << "Issue \##{issue.id} is closed. Reopen it and commit again"
|
412
|
+ end
|
413
|
+ if issue.assigned_to != user
|
414
|
+ if issue.assigned_to != nil
|
415
|
+ owner_info = "It belongs to #{issue.assigned_to.firstname} #{issue.assigned_to.lastname}"
|
416
|
+ else
|
417
|
+ owner_info = "It is unassigned"
|
418
|
+ end
|
419
|
+ errors << "Issue \##{issue.id} is not assigned to You. #{owner_info}"
|
420
|
+ end
|
421
|
+ end
|
422
|
+ return errors
|
423
|
+ end
|
424
|
+end
|
425
|
+
|
426
|
diff --git a/app/models/git_manager.rb b/app/models/git_manager.rb
|
427
|
new file mode 100644
|
428
|
index 0000000..2136144
|
429
|
--- /dev/null
|
430
|
+++ b/app/models/git_manager.rb
|
431
|
@@ -0,0 +1,256 @@
|
432
|
+require 'net/http'
|
433
|
+require 'uri'
|
434
|
+require 'redmine/scm/adapters/git_adapter'
|
435
|
+
|
436
|
+class GitManager
|
437
|
+ COMMANDS_READONLY = [
|
438
|
+ 'git-upload-pack',
|
439
|
+ ]
|
440
|
+ COMMANDS_WRITE = [
|
441
|
+ 'git-receive-pack',
|
442
|
+ ]
|
443
|
+ # TODO: make configurable
|
444
|
+ REPOSITORIES_ROOT='~/repositories/'
|
445
|
+ REDMINE_LOGIN_ENV_NAME='REDMINE_LOGIN'
|
446
|
+
|
447
|
+ def self.repositories_root
|
448
|
+ return File.expand_path(REPOSITORIES_ROOT)
|
449
|
+ end
|
450
|
+
|
451
|
+
|
452
|
+ # Executed by SSH when somebody logs into Redmine's SSH account
|
453
|
+ # using public key.
|
454
|
+ # Restricts the user to access only Git repositories he is allowed to.
|
455
|
+ def self.serve
|
456
|
+ begin
|
457
|
+ command = serve_get_original_command
|
458
|
+ user = serve_get_user
|
459
|
+ git_command, project_identifier = parse_git_command(command)
|
460
|
+ project, repository = find_project_and_repo(project_identifier)
|
461
|
+ role = user.role_for_project(project)
|
462
|
+
|
463
|
+ if COMMANDS_READONLY.include?(git_command)
|
464
|
+ if !role.allowed_to?(:view_changesets)
|
465
|
+ raise "User #{user} (#{role.name}) is not allowed to read project #{project}\n"
|
466
|
+ end
|
467
|
+ if !repository.scm.info
|
468
|
+ raise "Empty repository. Push some commit first"
|
469
|
+ end
|
470
|
+ elsif COMMANDS_WRITE.include?(git_command)
|
471
|
+ if !role.allowed_to?(:commit_access)
|
472
|
+ raise "User #{user} (#{role.name}) is not allowed to write to project #{project}\n"
|
473
|
+ end
|
474
|
+ if !repository.scm.info
|
475
|
+ warn "Creating new repository.\n"
|
476
|
+ repository.scm.init(project.description)
|
477
|
+ end
|
478
|
+ else
|
479
|
+ raise "Unknown command '#{verb}'"
|
480
|
+ end
|
481
|
+
|
482
|
+ rescue
|
483
|
+ warn "Error: #{$!}.\n"
|
484
|
+ exit 1
|
485
|
+ end
|
486
|
+
|
487
|
+ ENV[REDMINE_LOGIN_ENV_NAME]=user.login
|
488
|
+ exec 'git', 'shell', '-c', "#{git_command} '#{repository.url}'"
|
489
|
+ end
|
490
|
+
|
491
|
+ def self.get_authorized_keys_options_for_login(login)
|
492
|
+ return [ 'command="ruby ' + RAILS_ROOT + '/script/runner GitManager.serve \'' + login + '\' -e ' + ENV["RAILS_ENV"] +
|
493
|
+ '"', 'no-port-forwarding','no-X11-forwarding','no-agent-forwarding','no-pty' ]
|
494
|
+ end
|
495
|
+
|
496
|
+
|
497
|
+ private
|
498
|
+ def self.serve_get_original_command
|
499
|
+ command = ENV["SSH_ORIGINAL_COMMAND"]
|
500
|
+ if command == nil or command==""
|
501
|
+ raise "SSH_ORIGINAL_COMMAND not set. Use Git to access this account"
|
502
|
+ end
|
503
|
+ if command=~/\n/
|
504
|
+ raise "Command contains new line character"
|
505
|
+ end
|
506
|
+ return command
|
507
|
+ end
|
508
|
+
|
509
|
+ def self.serve_get_user
|
510
|
+ login = ARGV[0]
|
511
|
+ if login == nil or login==""
|
512
|
+ raise "Needs login as parameter"
|
513
|
+ end
|
514
|
+ user = User.find_by_login(login)
|
515
|
+ if user == nil
|
516
|
+ raise "User not found #{login}"
|
517
|
+ end
|
518
|
+ return user
|
519
|
+ end
|
520
|
+
|
521
|
+ def self.parse_git_command(command)
|
522
|
+ verb, args = command.split(" ",2)
|
523
|
+ if verb == 'git'
|
524
|
+ subverb, args = args.split(" ",2)
|
525
|
+ verb = "%s-%s" % [ verb, subverb ]
|
526
|
+ end
|
527
|
+ project_identifier = args.gsub("'","")
|
528
|
+ return verb, project_identifier
|
529
|
+ end
|
530
|
+
|
531
|
+ def self.find_project_and_repo(project_identifier)
|
532
|
+ project = Project.find_by_identifier(project_identifier)
|
533
|
+ if project == nil
|
534
|
+ raise "Project not found \"#{project_identifier}\""
|
535
|
+ end
|
536
|
+
|
537
|
+ repository = project.repository
|
538
|
+ if repository == nil
|
539
|
+ raise "Project #{project} does not have repository\n"
|
540
|
+ end
|
541
|
+
|
542
|
+ if repository.class != Repository::Git
|
543
|
+ raise "Project #{project} has non git repository #{repository.type}"
|
544
|
+ end
|
545
|
+ return project, repository
|
546
|
+ end
|
547
|
+
|
548
|
+
|
549
|
+ public
|
550
|
+
|
551
|
+ class RefCheck
|
552
|
+ @@checks = []
|
553
|
+
|
554
|
+ # Check Git ref, subclassess should override
|
555
|
+ def check(old_rev, new_rev, new_rev_type, branch, user, role, project, git)
|
556
|
+ return true
|
557
|
+ end
|
558
|
+
|
559
|
+ def self.inherited(subclass)
|
560
|
+ @@checks << subclass
|
561
|
+ end
|
562
|
+
|
563
|
+ def self.get_checks
|
564
|
+ return @@checks
|
565
|
+ end
|
566
|
+ end
|
567
|
+ class CommitCheck
|
568
|
+ @@checks = []
|
569
|
+
|
570
|
+ # Check Git ref, subclassess should override
|
571
|
+ def check(revision, branch, user, role, project, git)
|
572
|
+ return true
|
573
|
+ end
|
574
|
+
|
575
|
+ def self.inherited(subclass)
|
576
|
+ @@checks << subclass
|
577
|
+ end
|
578
|
+
|
579
|
+ def self.get_checks
|
580
|
+ return @@checks
|
581
|
+ end
|
582
|
+ end
|
583
|
+
|
584
|
+ def self.load_checks
|
585
|
+ files = Dir.glob(RAILS_ROOT + "/app/models/git_checks/*.rb")
|
586
|
+ files.each do |f|
|
587
|
+ f.sub!(/\A#{RAILS_ROOT}/,'')
|
588
|
+ f.split('/')[3..-1].join('/').split('.').first.camelize.constantize
|
589
|
+ end
|
590
|
+ end
|
591
|
+ load_checks
|
592
|
+
|
593
|
+ def self.check_commits
|
594
|
+ login = ENV[REDMINE_LOGIN_ENV_NAME]
|
595
|
+ if login == nil
|
596
|
+ warn "Redmine: Local user, not running checks"
|
597
|
+ exit 0
|
598
|
+ end
|
599
|
+
|
600
|
+ begin
|
601
|
+ user = User.find_by_login(login)
|
602
|
+ raise "User not found" if user == nil
|
603
|
+ repository = Repository.find_by_url(Dir.getwd)
|
604
|
+ raise "Repository not managed by Redmine" if repository == nil
|
605
|
+ raise "Non git repository" if repository.class != Repository::Git
|
606
|
+ project = repository.project
|
607
|
+ role = user.role_for_project(project)
|
608
|
+ git = repository.scm
|
609
|
+
|
610
|
+ warn ""
|
611
|
+ warn "-------------------------------------------------------------"
|
612
|
+ warn "Redmine is checking your changes for correctness..."
|
613
|
+ warn "Authenticated as #{user.name} (#{role.name} in #{project.name})"
|
614
|
+
|
615
|
+ error_found = false
|
616
|
+
|
617
|
+ warn "Changes:"
|
618
|
+ STDIN.each_line do |line|
|
619
|
+ old_rev, new_rev, branch = line.split(" ")
|
620
|
+
|
621
|
+ if new_rev == git.class::EMPTY_COMMIT
|
622
|
+ new_rev_type = "delete"
|
623
|
+ else
|
624
|
+ new_rev_type = git.get_object_type(new_rev)
|
625
|
+ end
|
626
|
+ revisions = nil
|
627
|
+ if new_rev_type == "commit"
|
628
|
+ revisions = git.revisions("", old_rev, new_rev)
|
629
|
+ end
|
630
|
+ warn " Ref: #{branch} type: #{new_rev_type}"
|
631
|
+
|
632
|
+ errors = []
|
633
|
+ # TODO: make checks configurable
|
634
|
+ RefCheck.get_checks.each do |check|
|
635
|
+ result = check.check(old_rev, new_rev, new_rev_type, branch, user, role, project, git)
|
636
|
+ if result.kind_of?(Array)
|
637
|
+ errors += result
|
638
|
+ else
|
639
|
+ errors << result
|
640
|
+ end
|
641
|
+ end
|
642
|
+ errors.each do |error|
|
643
|
+ warn " Error: #{error}"
|
644
|
+ end
|
645
|
+ error_found = true if !errors.empty?
|
646
|
+
|
647
|
+ if revisions != nil
|
648
|
+ revisions.each do |revision|
|
649
|
+ warn " Commit: #{revision.identifier}"
|
650
|
+
|
651
|
+ errors = []
|
652
|
+ CommitCheck.get_checks.each do |check|
|
653
|
+ result = check.check(revision, branch, user, role, project, git)
|
654
|
+ if result.kind_of?(Array)
|
655
|
+ errors += result
|
656
|
+ else
|
657
|
+ errors << result
|
658
|
+ end
|
659
|
+ end
|
660
|
+ errors.each do |error|
|
661
|
+ warn " Error: #{error}"
|
662
|
+ end
|
663
|
+ error_found = true if !errors.empty?
|
664
|
+ end
|
665
|
+ end
|
666
|
+ end
|
667
|
+ end
|
668
|
+
|
669
|
+ if error_found
|
670
|
+ if !role.allowed_to?(:manage_repository)
|
671
|
+ warn "Some commits were rejected. Correct them and try the push again."
|
672
|
+ warn "-------------------------------------------------------------"
|
673
|
+ warn ""
|
674
|
+ exit 1
|
675
|
+ else
|
676
|
+ warn "You are repository manager. Checks results are ignored. "
|
677
|
+ warn "-------------------------------------------------------------"
|
678
|
+ exit 0
|
679
|
+ end
|
680
|
+ end
|
681
|
+ warn "Changes look OK"
|
682
|
+ warn "-------------------------------------------------------------"
|
683
|
+ exit 0
|
684
|
+ end
|
685
|
+
|
686
|
+end
|
687
|
+
|
688
|
diff --git a/app/models/user.rb b/app/models/user.rb
|
689
|
index 9692390..c1606b6 100644
|
690
|
--- a/app/models/user.rb
|
691
|
+++ b/app/models/user.rb
|
692
|
@@ -65,6 +65,38 @@ class User < ActiveRecord::Base
|
693
|
validates_length_of :password, :minimum => 4, :allow_nil => true
|
694
|
validates_confirmation_of :password, :allow_nil => true
|
695
|
|
696
|
+ def ssh_key
|
697
|
+ return nil if ! Setting.serve_git_repositories?
|
698
|
+ load_ssh_key if @ssh_key_entry == nil
|
699
|
+ return @ssh_key_entry.key
|
700
|
+ end
|
701
|
+
|
702
|
+ def ssh_key_type
|
703
|
+ return nil if ! Setting.serve_git_repositories?
|
704
|
+ load_ssh_key if @ssh_key_entry == nil
|
705
|
+ return @ssh_key_entry.type
|
706
|
+ end
|
707
|
+
|
708
|
+ def ssh_key=(key)
|
709
|
+ return if ! Setting.serve_git_repositories?
|
710
|
+ new_ssh_key if @ssh_key_entry == nil
|
711
|
+ key = key.strip if key != nil
|
712
|
+ @ssh_key_entry.key = key
|
713
|
+ end
|
714
|
+
|
715
|
+ def ssh_key_type=(key_type)
|
716
|
+ return if ! Setting.serve_git_repositories?
|
717
|
+ new_ssh_key if @ssh_key_entry == nil
|
718
|
+ @ssh_key_entry.type = key_type
|
719
|
+ end
|
720
|
+
|
721
|
+ def validate
|
722
|
+ return if !Setting.serve_git_repositories?
|
723
|
+ return if @ssh_key_entry == nil
|
724
|
+
|
725
|
+ errors.add(:ssh_key, "is not valid") if !@ssh_key_entry.validate
|
726
|
+ end
|
727
|
+
|
728
|
def before_create
|
729
|
self.mail_notification = false
|
730
|
true
|
731
|
@@ -74,6 +106,15 @@ class User < ActiveRecord::Base
|
732
|
# update hashed_password if password was set
|
733
|
self.hashed_password = User.hash_password(self.password) if self.password
|
734
|
end
|
735
|
+
|
736
|
+ def after_save
|
737
|
+ return if ! Setting.serve_git_repositories?
|
738
|
+ return if @ssh_key_entry == nil
|
739
|
+
|
740
|
+ @ssh_key_entry.options = GitManager.get_authorized_keys_options_for_login(login)
|
741
|
+
|
742
|
+ @ssh_key_entry.save
|
743
|
+ end
|
744
|
|
745
|
def reload(*args)
|
746
|
@name = nil
|
747
|
@@ -271,6 +312,16 @@ private
|
748
|
def self.hash_password(clear_password)
|
749
|
Digest::SHA1.hexdigest(clear_password || "")
|
750
|
end
|
751
|
+
|
752
|
+ def new_ssh_key
|
753
|
+ @ssh_key_entry = AuthorizedKeysEntry.new
|
754
|
+ @ssh_key_entry.identifier = login
|
755
|
+ end
|
756
|
+
|
757
|
+ def load_ssh_key
|
758
|
+ @ssh_key_entry = AuthorizedKeysEntry.find_by_identifier(login)
|
759
|
+ new_ssh_key if @ssh_key_entry == nil
|
760
|
+ end
|
761
|
end
|
762
|
|
763
|
class AnonymousUser < User
|
764
|
diff --git a/app/views/my/account.rhtml b/app/views/my/account.rhtml
|
765
|
index f4b726f..448cc33 100644
|
766
|
--- a/app/views/my/account.rhtml
|
767
|
+++ b/app/views/my/account.rhtml
|
768
|
@@ -15,6 +15,11 @@
|
769
|
<p><%= f.text_field :lastname, :required => true %></p>
|
770
|
<p><%= f.text_field :mail, :required => true %></p>
|
771
|
<p><%= f.select :language, lang_options_for_select %></p>
|
772
|
+<% if Setting.serve_git_repositories? %>
|
773
|
+ <p><%= f.select :ssh_key_type, AuthorizedKeysEntry::KEY_TYPES %></p>
|
774
|
+ <p><%= f.text_area :ssh_key, :rows => 10 %></p>
|
775
|
+<% end %>
|
776
|
+
|
777
|
</div>
|
778
|
|
779
|
<%= submit_tag l(:button_save) %>
|
780
|
diff --git a/app/views/settings/_repositories.rhtml b/app/views/settings/_repositories.rhtml
|
781
|
index a8c9244..189648f 100644
|
782
|
--- a/app/views/settings/_repositories.rhtml
|
783
|
+++ b/app/views/settings/_repositories.rhtml
|
784
|
@@ -14,6 +14,14 @@
|
785
|
<%= hidden_field_tag 'settings[enabled_scm][]', '' %>
|
786
|
</p>
|
787
|
|
788
|
+<% # TODO: Should be disabled when Git SCM is not enabled
|
789
|
+%>
|
790
|
+<p><label><%= l(:setting_serve_git_repositories) %></label>
|
791
|
+<%= check_box_tag 'settings[serve_git_repositories]', 1, Setting.serve_git_repositories? %>
|
792
|
+<%= hidden_field_tag 'settings[serve_git_repositories]', 0 %>
|
793
|
+</p>
|
794
|
+
|
795
|
+
|
796
|
<p><label><%= l(:setting_repositories_encodings) %></label>
|
797
|
<%= text_field_tag 'settings[repositories_encodings]', Setting.repositories_encodings, :size => 60 %><br /><em><%= l(:text_comma_separated) %></em></p>
|
798
|
|
799
|
diff --git a/config/settings.yml b/config/settings.yml
|
800
|
index 5006445..a3af36c 100644
|
801
|
--- a/config/settings.yml
|
802
|
+++ b/config/settings.yml
|
803
|
@@ -77,6 +77,8 @@ autofetch_changesets:
|
804
|
default: 1
|
805
|
sys_api_enabled:
|
806
|
default: 0
|
807
|
+serve_git_repositories:
|
808
|
+ default: 0
|
809
|
commit_ref_keywords:
|
810
|
default: 'refs,references,IssueID'
|
811
|
commit_fix_keywords:
|
812
|
diff --git a/lang/bg.yml b/lang/bg.yml
|
813
|
index 61f7520..b9acd01 100644
|
814
|
--- a/lang/bg.yml
|
815
|
+++ b/lang/bg.yml
|
816
|
@@ -92,6 +92,8 @@ field_is_required: Задължително
|
817
|
field_firstname: Име
|
818
|
field_lastname: Фамилия
|
819
|
field_mail: Email
|
820
|
+field_ssh_key: SSH Public Key
|
821
|
+field_ssh_key_type: SSH Public Key Type
|
822
|
field_filename: Файл
|
823
|
field_filesize: Големина
|
824
|
field_downloads: Downloads
|
825
|
@@ -181,6 +183,7 @@ setting_wiki_compression: Wiki компресиране на историята
|
826
|
setting_feeds_limit: Лимит на Feeds
|
827
|
setting_autofetch_changesets: Автоматично обработване на ревизиите
|
828
|
setting_sys_api_enabled: Разрешаване на WS за управление
|
829
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
830
|
setting_commit_ref_keywords: Отбелязващи ключови думи
|
831
|
setting_commit_fix_keywords: Приключващи ключови думи
|
832
|
setting_autologin: Автоматичен вход
|
833
|
diff --git a/lang/ca.yml b/lang/ca.yml
|
834
|
index 0ce265f..b1bdcc7 100644
|
835
|
--- a/lang/ca.yml
|
836
|
+++ b/lang/ca.yml
|
837
|
@@ -106,6 +106,8 @@ field_is_required: Necessari
|
838
|
field_firstname: Nom
|
839
|
field_lastname: Cognom
|
840
|
field_mail: Correu electrònic
|
841
|
+field_ssh_key: SSH Public Key
|
842
|
+field_ssh_key_type: SSH Public Key Type
|
843
|
field_filename: Fitxer
|
844
|
field_filesize: Mida
|
845
|
field_downloads: Baixades
|
846
|
@@ -202,6 +204,7 @@ setting_feeds_limit: Límit de contingut del canal
|
847
|
setting_default_projects_public: Els projectes nous són públics per defecte
|
848
|
setting_autofetch_changesets: Omple automàticament les publicacions
|
849
|
setting_sys_api_enabled: Habilita el WS per a la gestió del dipòsit
|
850
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
851
|
setting_commit_ref_keywords: Paraules claus per a la referència
|
852
|
setting_commit_fix_keywords: Paraules claus per a la correcció
|
853
|
setting_autologin: Entrada automàtica
|
854
|
diff --git a/lang/cs.yml b/lang/cs.yml
|
855
|
index 534da67..a50733b 100644
|
856
|
--- a/lang/cs.yml
|
857
|
+++ b/lang/cs.yml
|
858
|
@@ -106,6 +106,8 @@ field_is_required: Povinné pole
|
859
|
field_firstname: Jméno
|
860
|
field_lastname: Příjmení
|
861
|
field_mail: Email
|
862
|
+field_ssh_key: SSH Public Key
|
863
|
+field_ssh_key_type: SSH Public Key Type
|
864
|
field_filename: Soubor
|
865
|
field_filesize: Velikost
|
866
|
field_downloads: Staženo
|
867
|
@@ -201,6 +203,7 @@ setting_feeds_limit: Feed content limit
|
868
|
setting_default_projects_public: Nové projekty nastavovat jako veřejné
|
869
|
setting_autofetch_changesets: Autofetch commits
|
870
|
setting_sys_api_enabled: Povolit WS pro správu repozitory
|
871
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
872
|
setting_commit_ref_keywords: Klíčová slova pro odkazy
|
873
|
setting_commit_fix_keywords: Klíčová slova pro uzavření
|
874
|
setting_autologin: Automatické přihlašování
|
875
|
diff --git a/lang/da.yml b/lang/da.yml
|
876
|
index 2edbc52..a1bf133 100644
|
877
|
--- a/lang/da.yml
|
878
|
+++ b/lang/da.yml
|
879
|
@@ -106,6 +106,8 @@ field_is_required: Skal udfyldes
|
880
|
field_firstname: Fornavn
|
881
|
field_lastname: Efternavn
|
882
|
field_mail: E-mail
|
883
|
+field_ssh_key: SSH Public Key
|
884
|
+field_ssh_key_type: SSH Public Key Type
|
885
|
field_filename: Fil
|
886
|
field_filesize: Størrelse
|
887
|
field_downloads: Downloads
|
888
|
@@ -204,6 +206,7 @@ setting_autofetch_changesets: Hent automatisk commits
|
889
|
setting_sys_api_enabled: Aktiver webservice til versionsstyring
|
890
|
setting_commit_ref_keywords: Nøgleord for sagsreferencer
|
891
|
setting_commit_fix_keywords: Nøgleord for lukning af sager
|
892
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
893
|
setting_autologin: Autologin
|
894
|
setting_date_format: Datoformat
|
895
|
setting_time_format: Tidsformat
|
896
|
diff --git a/lang/de.yml b/lang/de.yml
|
897
|
index c403b48..2362c41 100644
|
898
|
--- a/lang/de.yml
|
899
|
+++ b/lang/de.yml
|
900
|
@@ -106,6 +106,8 @@ field_is_required: Erforderlich
|
901
|
field_firstname: Vorname
|
902
|
field_lastname: Nachname
|
903
|
field_mail: E-Mail
|
904
|
+field_ssh_key: SSH Public Key
|
905
|
+field_ssh_key_type: SSH Public Key Type
|
906
|
field_filename: Datei
|
907
|
field_filesize: Größe
|
908
|
field_downloads: Downloads
|
909
|
@@ -203,6 +205,7 @@ setting_feeds_limit: Max. Anzahl Einträge pro Atom-Feed
|
910
|
setting_default_projects_public: Neue Projekte sind standardmäßig öffentlich
|
911
|
setting_autofetch_changesets: Changesets automatisch abrufen
|
912
|
setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen
|
913
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
914
|
setting_commit_ref_keywords: Schlüsselwörter (Beziehungen)
|
915
|
setting_commit_fix_keywords: Schlüsselwörter (Status)
|
916
|
setting_autologin: Automatische Anmeldung
|
917
|
diff --git a/lang/en.yml b/lang/en.yml
|
918
|
index dad948e..f2a4ca3 100644
|
919
|
--- a/lang/en.yml
|
920
|
+++ b/lang/en.yml
|
921
|
@@ -108,6 +108,8 @@ field_is_required: Required
|
922
|
field_firstname: Firstname
|
923
|
field_lastname: Lastname
|
924
|
field_mail: Email
|
925
|
+field_ssh_key: SSH Public Key
|
926
|
+field_ssh_key_type: SSH Public Key Type
|
927
|
field_filename: File
|
928
|
field_filesize: Size
|
929
|
field_downloads: Downloads
|
930
|
@@ -205,6 +207,7 @@ setting_feeds_limit: Feed content limit
|
931
|
setting_default_projects_public: New projects are public by default
|
932
|
setting_autofetch_changesets: Autofetch commits
|
933
|
setting_sys_api_enabled: Enable WS for repository management
|
934
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
935
|
setting_commit_ref_keywords: Referencing keywords
|
936
|
setting_commit_fix_keywords: Fixing keywords
|
937
|
setting_autologin: Autologin
|
938
|
diff --git a/lang/es.yml b/lang/es.yml
|
939
|
index 1729292..b979921 100644
|
940
|
--- a/lang/es.yml
|
941
|
+++ b/lang/es.yml
|
942
|
@@ -150,6 +150,8 @@ field_last_login_on: Última conexión
|
943
|
field_lastname: Apellido
|
944
|
field_login: Identificador
|
945
|
field_mail: Correo electrónico
|
946
|
+field_ssh_key: SSH Public Key
|
947
|
+field_ssh_key_type: SSH Public Key Type
|
948
|
field_mail_notification: Notificaciones por correo
|
949
|
field_max_length: Longitud máxima
|
950
|
field_min_length: Longitud mínima
|
951
|
@@ -627,6 +629,7 @@ setting_repositories_encodings: Codificaciones del repositorio
|
952
|
setting_self_registration: Registro permitido
|
953
|
setting_sequential_project_identifiers: Generar identificadores de proyecto
|
954
|
setting_sys_api_enabled: Habilitar SW para la gestión del repositorio
|
955
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
956
|
setting_text_formatting: Formato de texto
|
957
|
setting_time_format: Formato de hora
|
958
|
setting_user_format: Formato de nombre de usuario
|
959
|
diff --git a/lang/fi.yml b/lang/fi.yml
|
960
|
index 244f858..12b7db7 100644
|
961
|
--- a/lang/fi.yml
|
962
|
+++ b/lang/fi.yml
|
963
|
@@ -101,6 +101,8 @@ field_is_required: Vaaditaan
|
964
|
field_firstname: Etunimi
|
965
|
field_lastname: Sukunimi
|
966
|
field_mail: Sähköposti
|
967
|
+field_ssh_key: SSH Public Key
|
968
|
+field_ssh_key_type: SSH Public Key Type
|
969
|
field_filename: Tiedosto
|
970
|
field_filesize: Koko
|
971
|
field_downloads: Latausta
|
972
|
@@ -194,6 +196,7 @@ setting_wiki_compression: Wiki historian pakkaus
|
973
|
setting_feeds_limit: Syötteen sisällön raja
|
974
|
setting_autofetch_changesets: Automaattisten muutosjoukkojen haku
|
975
|
setting_sys_api_enabled: Salli WS tietovaraston hallintaan
|
976
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
977
|
setting_commit_ref_keywords: Viittaavat hakusanat
|
978
|
setting_commit_fix_keywords: Korjaavat hakusanat
|
979
|
setting_autologin: Automaatinen kirjautuminen
|
980
|
diff --git a/lang/fr.yml b/lang/fr.yml
|
981
|
index 374a0d8..dc6b772 100644
|
982
|
--- a/lang/fr.yml
|
983
|
+++ b/lang/fr.yml
|
984
|
@@ -108,6 +108,8 @@ field_is_required: Obligatoire
|
985
|
field_firstname: Prénom
|
986
|
field_lastname: Nom
|
987
|
field_mail: Email
|
988
|
+field_ssh_key: SSH Public Key
|
989
|
+field_ssh_key_type: SSH Public Key Type
|
990
|
field_filename: Fichier
|
991
|
field_filesize: Taille
|
992
|
field_downloads: Téléchargements
|
993
|
@@ -205,6 +207,7 @@ setting_feeds_limit: Limite du contenu des flux RSS
|
994
|
setting_default_projects_public: Définir les nouveaux projects comme publics par défaut
|
995
|
setting_autofetch_changesets: Récupération auto. des commits
|
996
|
setting_sys_api_enabled: Activer les WS pour la gestion des dépôts
|
997
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
998
|
setting_commit_ref_keywords: Mot-clés de référencement
|
999
|
setting_commit_fix_keywords: Mot-clés de résolution
|
1000
|
setting_autologin: Autologin
|
1001
|
diff --git a/lang/he.yml b/lang/he.yml
|
1002
|
index b10b732..8abfb0e 100644
|
1003
|
--- a/lang/he.yml
|
1004
|
+++ b/lang/he.yml
|
1005
|
@@ -94,6 +94,8 @@ field_is_required: נדרש
|
1006
|
field_firstname: שם פרטי
|
1007
|
field_lastname: שם משפחה
|
1008
|
field_mail: דוא"ל
|
1009
|
+field_ssh_key: SSH Public Key
|
1010
|
+field_ssh_key_type: SSH Public Key Type
|
1011
|
field_filename: קובץ
|
1012
|
field_filesize: גודל
|
1013
|
field_downloads: הורדות
|
1014
|
@@ -184,6 +186,7 @@ setting_wiki_compression: כיווץ היסטורית WIKI
|
1015
|
setting_feeds_limit: גבול תוכן הזנות
|
1016
|
setting_autofetch_changesets: משיכה אוטומתי של עידכונים
|
1017
|
setting_sys_api_enabled: אפשר WS לניהול המאגר
|
1018
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1019
|
setting_commit_ref_keywords: מילות מפתח מקשרות
|
1020
|
setting_commit_fix_keywords: מילות מפתח מתקנות
|
1021
|
setting_autologin: חיבור אוטומטי
|
1022
|
diff --git a/lang/hu.yml b/lang/hu.yml
|
1023
|
index 059b3ee..1c95590 100644
|
1024
|
--- a/lang/hu.yml
|
1025
|
+++ b/lang/hu.yml
|
1026
|
@@ -103,6 +103,8 @@ field_is_required: Kötelező
|
1027
|
field_firstname: Keresztnév
|
1028
|
field_lastname: Vezetéknév
|
1029
|
field_mail: E-mail
|
1030
|
+field_ssh_key: SSH Public Key
|
1031
|
+field_ssh_key_type: SSH Public Key Type
|
1032
|
field_filename: Fájl
|
1033
|
field_filesize: Méret
|
1034
|
field_downloads: Letöltések
|
1035
|
@@ -198,6 +200,7 @@ setting_feeds_limit: RSS tartalom korlát
|
1036
|
setting_default_projects_public: Az új projektek alapértelmezés szerint nyilvánosak
|
1037
|
setting_autofetch_changesets: Commitok automatikus lehúzása
|
1038
|
setting_sys_api_enabled: WS engedélyezése a tárolók kezeléséhez
|
1039
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1040
|
setting_commit_ref_keywords: Hivatkozó kulcsszavak
|
1041
|
setting_commit_fix_keywords: Javítások kulcsszavai
|
1042
|
setting_autologin: Automatikus bejelentkezés
|
1043
|
diff --git a/lang/it.yml b/lang/it.yml
|
1044
|
index f3798b4..db35a4a 100644
|
1045
|
--- a/lang/it.yml
|
1046
|
+++ b/lang/it.yml
|
1047
|
@@ -92,6 +92,8 @@ field_is_required: Richiesto
|
1048
|
field_firstname: Nome
|
1049
|
field_lastname: Cognome
|
1050
|
field_mail: Email
|
1051
|
+field_ssh_key: SSH Public Key
|
1052
|
+field_ssh_key_type: SSH Public Key Type
|
1053
|
field_filename: File
|
1054
|
field_filesize: Dimensione
|
1055
|
field_downloads: Download
|
1056
|
@@ -181,6 +183,7 @@ setting_wiki_compression: Comprimi cronologia wiki
|
1057
|
setting_feeds_limit: Limite contenuti del feed
|
1058
|
setting_autofetch_changesets: Acquisisci automaticamente le commit
|
1059
|
setting_sys_api_enabled: Abilita WS per la gestione del repository
|
1060
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1061
|
setting_commit_ref_keywords: Referencing keywords
|
1062
|
setting_commit_fix_keywords: Fixing keywords
|
1063
|
setting_autologin: Login automatico
|
1064
|
diff --git a/lang/ja.yml b/lang/ja.yml
|
1065
|
index c1279b3..0875e66 100644
|
1066
|
--- a/lang/ja.yml
|
1067
|
+++ b/lang/ja.yml
|
1068
|
@@ -93,6 +93,8 @@ field_is_required: 必須
|
1069
|
field_firstname: 名前
|
1070
|
field_lastname: 苗字
|
1071
|
field_mail: メールアドレス
|
1072
|
+field_ssh_key: SSH Public Key
|
1073
|
+field_ssh_key_type: SSH Public Key Type
|
1074
|
field_filename: ファイル
|
1075
|
field_filesize: サイズ
|
1076
|
field_downloads: ダウンロード
|
1077
|
@@ -182,6 +184,7 @@ setting_wiki_compression: Wiki履歴を圧縮する
|
1078
|
setting_feeds_limit: フィード内容の上限
|
1079
|
setting_autofetch_changesets: コミットを自動取得する
|
1080
|
setting_sys_api_enabled: リポジトリ管理用のWeb Serviceを有効にする
|
1081
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1082
|
setting_commit_ref_keywords: 参照用キーワード
|
1083
|
setting_commit_fix_keywords: 修正用キーワード
|
1084
|
setting_autologin: 自動ログイン
|
1085
|
diff --git a/lang/ko.yml b/lang/ko.yml
|
1086
|
index f7958f9..3818080 100644
|
1087
|
--- a/lang/ko.yml
|
1088
|
+++ b/lang/ko.yml
|
1089
|
@@ -94,6 +94,8 @@ field_is_required: 필수
|
1090
|
field_firstname: 이름
|
1091
|
field_lastname: 성
|
1092
|
field_mail: 메일
|
1093
|
+field_ssh_key: SSH Public Key
|
1094
|
+field_ssh_key_type: SSH Public Key Type
|
1095
|
field_filename: 파일
|
1096
|
field_filesize: 크기
|
1097
|
field_downloads: 다운로드
|
1098
|
@@ -184,6 +186,7 @@ setting_wiki_compression: 위키 이력 압축
|
1099
|
setting_feeds_limit: 내용 피드(RSS Feed) 제한 개수
|
1100
|
setting_autofetch_changesets: 커밋된 변경묶음을 자동으로 가져오기
|
1101
|
setting_sys_api_enabled: 저장소 관리자에 WS 를 허용
|
1102
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1103
|
setting_commit_ref_keywords: 일감 참조에 사용할 키워드들
|
1104
|
setting_commit_fix_keywords: 일감 해결에 사용할 키워드들
|
1105
|
setting_autologin: 자동 로그인
|
1106
|
diff --git a/lang/lt.yml b/lang/lt.yml
|
1107
|
index 3cdbcf0..ca56fb8 100644
|
1108
|
--- a/lang/lt.yml
|
1109
|
+++ b/lang/lt.yml
|
1110
|
@@ -106,6 +106,8 @@ field_is_required: Reikalaujama
|
1111
|
field_firstname: Vardas
|
1112
|
field_lastname: Pavardė
|
1113
|
field_mail: Email
|
1114
|
+field_ssh_key: SSH Public Key
|
1115
|
+field_ssh_key_type: SSH Public Key Type
|
1116
|
field_filename: Byla
|
1117
|
field_filesize: Dydis
|
1118
|
field_downloads: Atsiuntimai
|
1119
|
@@ -203,6 +205,7 @@ setting_feeds_limit: Perdavimo turinio riba
|
1120
|
setting_default_projects_public: Naujas projektas viešas pagal nutylėjimą
|
1121
|
setting_autofetch_changesets: Automatinis pakeitimų siuntimas
|
1122
|
setting_sys_api_enabled: Įgalinkite WS sandėlio vadybai
|
1123
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1124
|
setting_commit_ref_keywords: Nurodymo reikšminiai žodžiai
|
1125
|
setting_commit_fix_keywords: Fiksavimo reikšminiai žodžiai
|
1126
|
setting_autologin: Autoregistracija
|
1127
|
diff --git a/lang/nl.yml b/lang/nl.yml
|
1128
|
index ed10b4d..1d2bcbc 100644
|
1129
|
--- a/lang/nl.yml
|
1130
|
+++ b/lang/nl.yml
|
1131
|
@@ -148,6 +148,8 @@ field_attr_mail: E-mail attribuut
|
1132
|
field_onthefly: On-the-fly aanmaken van een gebruiker
|
1133
|
field_start_date: Start
|
1134
|
field_done_ratio: %% Gereed
|
1135
|
+field_ssh_key: SSH Public Key
|
1136
|
+field_ssh_key_type: SSH Public Key Type
|
1137
|
field_auth_source: Authenticatiemethode
|
1138
|
field_hide_mail: Verberg mijn e-mailadres
|
1139
|
field_comments: Commentaar
|
1140
|
@@ -638,6 +640,7 @@ field_parent_title: Bovenliggende pagina
|
1141
|
label_issue_watchers: Monitoren
|
1142
|
setting_commit_logs_encoding: Encodering van commit berichten
|
1143
|
button_quote: Citaat
|
1144
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1145
|
setting_sequential_project_identifiers: Genereer sequentiële projectidentiteiten
|
1146
|
notice_unable_delete_version: Niet mogelijk om deze versie te verwijderen.
|
1147
|
label_renamed: hernoemd
|
1148
|
diff --git a/lang/no.yml b/lang/no.yml
|
1149
|
index c8f131f..aa9c843 100644
|
1150
|
--- a/lang/no.yml
|
1151
|
+++ b/lang/no.yml
|
1152
|
@@ -105,6 +105,8 @@ field_is_required: Kreves
|
1153
|
field_firstname: Fornavn
|
1154
|
field_lastname: Etternavn
|
1155
|
field_mail: E-post
|
1156
|
+field_ssh_key: SSH Public Key
|
1157
|
+field_ssh_key_type: SSH Public Key Type
|
1158
|
field_filename: Fil
|
1159
|
field_filesize: Størrelse
|
1160
|
field_downloads: Nedlastinger
|
1161
|
@@ -200,6 +202,7 @@ setting_feeds_limit: Innholdsgrense for Feed
|
1162
|
setting_default_projects_public: Nye prosjekter er offentlige som standard
|
1163
|
setting_autofetch_changesets: Autohenting av innsendinger
|
1164
|
setting_sys_api_enabled: Aktiver webservice for depot-administrasjon
|
1165
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1166
|
setting_commit_ref_keywords: Nøkkelord for referanse
|
1167
|
setting_commit_fix_keywords: Nøkkelord for retting
|
1168
|
setting_autologin: Autoinnlogging
|
1169
|
diff --git a/lang/pl.yml b/lang/pl.yml
|
1170
|
index 6b28f0e..31c2dae 100644
|
1171
|
--- a/lang/pl.yml
|
1172
|
+++ b/lang/pl.yml
|
1173
|
@@ -161,6 +161,8 @@ field_last_login_on: Ostatnie połączenie
|
1174
|
field_lastname: Nazwisko
|
1175
|
field_login: Login
|
1176
|
field_mail: Email
|
1177
|
+field_ssh_key: Klucz publiczny SSH
|
1178
|
+field_ssh_key_type: Typ klucza SSH
|
1179
|
field_mail_notification: Powiadomienia Email
|
1180
|
field_max_length: Maksymalna długość
|
1181
|
field_min_length: Minimalna długość
|
1182
|
@@ -657,6 +659,7 @@ setting_repositories_encodings: Kodowanie repozytoriów
|
1183
|
setting_self_registration: Własna rejestracja umożliwiona
|
1184
|
setting_sequential_project_identifiers: Generuj sekwencyjne identyfikatory projektów
|
1185
|
setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium
|
1186
|
+setting_serve_git_repositories: Udostępnij repozytoria GIT poprzez konto SSH Redmine
|
1187
|
setting_text_formatting: Formatowanie tekstu
|
1188
|
setting_time_format: Format czasu
|
1189
|
setting_user_format: Personalny format wyświetlania
|
1190
|
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
|
1191
|
index ecbbc0c..716a1d7 100644
|
1192
|
--- a/lang/pt-br.yml
|
1193
|
+++ b/lang/pt-br.yml
|
1194
|
@@ -105,6 +105,8 @@ field_is_required: Obrigatório
|
1195
|
field_firstname: Nome
|
1196
|
field_lastname: Sobrenome
|
1197
|
field_mail: Email
|
1198
|
+field_ssh_key: SSH Public Key
|
1199
|
+field_ssh_key_type: SSH Public Key Type
|
1200
|
field_filename: Arquivo
|
1201
|
field_filesize: Tamanho
|
1202
|
field_downloads: Downloads
|
1203
|
@@ -201,6 +203,7 @@ setting_feeds_limit: Limite do Feed
|
1204
|
setting_default_projects_public: Novos projetos são públicos por padrão
|
1205
|
setting_autofetch_changesets: Auto-obter commits
|
1206
|
setting_sys_api_enabled: Ativa WS para gerenciamento do repositório
|
1207
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1208
|
setting_commit_ref_keywords: Palavras de referência
|
1209
|
setting_commit_fix_keywords: Palavras de fechamento
|
1210
|
setting_autologin: Auto-login
|
1211
|
diff --git a/lang/pt.yml b/lang/pt.yml
|
1212
|
index ec42386..6149d34 100644
|
1213
|
--- a/lang/pt.yml
|
1214
|
+++ b/lang/pt.yml
|
1215
|
@@ -107,6 +107,8 @@ field_is_required: Obrigatório
|
1216
|
field_firstname: Nome
|
1217
|
field_lastname: Apelido
|
1218
|
field_mail: E-mail
|
1219
|
+field_ssh_key: SSH Public Key
|
1220
|
+field_ssh_key_type: SSH Public Key Type
|
1221
|
field_filename: Ficheiro
|
1222
|
field_filesize: Tamanho
|
1223
|
field_downloads: Downloads
|
1224
|
@@ -203,6 +205,7 @@ setting_feeds_limit: Limite de conteúdo do feed
|
1225
|
setting_default_projects_public: Projectos novos são públicos por omissão
|
1226
|
setting_autofetch_changesets: Buscar automaticamente commits
|
1227
|
setting_sys_api_enabled: Activar Web Service para gestão do repositório
|
1228
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1229
|
setting_commit_ref_keywords: Palavras-chave de referência
|
1230
|
setting_commit_fix_keywords: Palavras-chave de fecho
|
1231
|
setting_autologin: Login automático
|
1232
|
diff --git a/lang/ro.yml b/lang/ro.yml
|
1233
|
index b0df48d..25be71e 100644
|
1234
|
--- a/lang/ro.yml
|
1235
|
+++ b/lang/ro.yml
|
1236
|
@@ -92,6 +92,8 @@ field_is_required: Obligatoriu
|
1237
|
field_firstname: Nume
|
1238
|
field_lastname: Prenume
|
1239
|
field_mail: Email
|
1240
|
+field_ssh_key: SSH Public Key
|
1241
|
+field_ssh_key_type: SSH Public Key Type
|
1242
|
field_filename: Fisier
|
1243
|
field_filesize: Marimea fisierului
|
1244
|
field_downloads: Download
|
1245
|
@@ -181,6 +183,7 @@ setting_wiki_compression: Compresie istoric wiki
|
1246
|
setting_feeds_limit: Limita continut feed
|
1247
|
setting_autofetch_changesets: Autofetch commits
|
1248
|
setting_sys_api_enabled: Setare WS pentru managementul stocului (repository)
|
1249
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1250
|
setting_commit_ref_keywords: Cuvinte cheie de referinta
|
1251
|
setting_commit_fix_keywords: Cuvinte cheie de rezolvare
|
1252
|
setting_autologin: Autentificare automata
|
1253
|
diff --git a/lang/ru.yml b/lang/ru.yml
|
1254
|
index 4943eea..91db5b1 100644
|
1255
|
--- a/lang/ru.yml
|
1256
|
+++ b/lang/ru.yml
|
1257
|
@@ -165,6 +165,8 @@ field_last_login_on: Последнее подключение
|
1258
|
field_lastname: Фамилия
|
1259
|
field_login: Пользователь
|
1260
|
field_mail: Email
|
1261
|
+field_ssh_key: SSH Public Key
|
1262
|
+field_ssh_key_type: SSH Public Key Type
|
1263
|
field_mail_notification: Уведомления по email
|
1264
|
field_max_length: Максимальная длина
|
1265
|
field_min_length: Минимальная длина
|
1266
|
@@ -673,6 +675,7 @@ setting_repositories_encodings: Кодировки хранилища
|
1267
|
setting_self_registration: Возможна саморегистрация
|
1268
|
setting_sequential_project_identifiers: Генерировать последовательные идентификаторы проектов
|
1269
|
setting_sys_api_enabled: Разрешить WS для управления хранилищем
|
1270
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1271
|
setting_text_formatting: Форматирование текста
|
1272
|
setting_time_format: Формат времени
|
1273
|
setting_user_format: Формат отображения имени
|
1274
|
diff --git a/lang/sk.yml b/lang/sk.yml
|
1275
|
index ffae2d6..5297432 100644
|
1276
|
--- a/lang/sk.yml
|
1277
|
+++ b/lang/sk.yml
|
1278
|
@@ -106,6 +106,8 @@ field_is_required: Povinné pole
|
1279
|
field_firstname: Meno
|
1280
|
field_lastname: Priezvisko
|
1281
|
field_mail: Email
|
1282
|
+field_ssh_key: SSH Public Key
|
1283
|
+field_ssh_key_type: SSH Public Key Type
|
1284
|
field_filename: Súbor
|
1285
|
field_filesize: Veľkosť
|
1286
|
field_downloads: Stiahnuté
|
1287
|
@@ -201,6 +203,7 @@ setting_feeds_limit: Limit zobrazených položiek (Atom feed)
|
1288
|
setting_default_projects_public: Nové projekty nastavovať ako verejné
|
1289
|
setting_autofetch_changesets: Automatický prenos zmien
|
1290
|
setting_sys_api_enabled: Povolit WS pre správu repozitory
|
1291
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1292
|
setting_commit_ref_keywords: Klúčové slová pre odkazy
|
1293
|
setting_commit_fix_keywords: Klúčové slová pre uzavretie
|
1294
|
setting_autologin: Automatické prihlasovanie
|
1295
|
@@ -698,10 +701,10 @@ label_example: Príklad
|
1296
|
permission_edit_own_messages: Edit own messages
|
1297
|
permission_delete_own_messages: Delete own messages
|
1298
|
text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped."
|
1299
|
-label_user_activity: "%s's activity"
|
1300
|
-label_updated_time_by: Updated by %s %s ago
|
1301
|
-text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.'
|
1302
|
-setting_diff_max_lines_displayed: Max number of diff lines displayed
|
1303
|
-text_plugin_assets_writable: Plugin assets directory writable
|
1304
|
-warning_attachments_not_saved: "%d file(s) could not be saved."
|
1305
|
-button_create_and_continue: Create and continue
|
1306
|
+label_user_activity: "%s's activity"
|
1307
|
+label_updated_time_by: Updated by %s %s ago
|
1308
|
+text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.'
|
1309
|
+setting_diff_max_lines_displayed: Max number of diff lines displayed
|
1310
|
+text_plugin_assets_writable: Plugin assets directory writable
|
1311
|
+warning_attachments_not_saved: "%d file(s) could not be saved."
|
1312
|
+button_create_and_continue: Create and continue
|
1313
|
diff --git a/lang/sr.yml b/lang/sr.yml
|
1314
|
index 7070c4a..39031e6 100644
|
1315
|
--- a/lang/sr.yml
|
1316
|
+++ b/lang/sr.yml
|
1317
|
@@ -96,6 +96,8 @@ field_is_required: Zahtevano
|
1318
|
field_firstname: Ime
|
1319
|
field_lastname: Prezime
|
1320
|
field_mail: Email
|
1321
|
+field_ssh_key: SSH Public Key
|
1322
|
+field_ssh_key_type: SSH Public Key Type
|
1323
|
field_filename: Fajl
|
1324
|
field_filesize: Veličina
|
1325
|
field_downloads: Preuzimanja
|
1326
|
@@ -186,6 +188,7 @@ setting_wiki_compression: Kompresija wiki history-a
|
1327
|
setting_feeds_limit: Feed content limit
|
1328
|
setting_autofetch_changesets: Autofetch commits
|
1329
|
setting_sys_api_enabled: Ukljuci WS za menadžment spremišta
|
1330
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1331
|
setting_commit_ref_keywords: Referentne ključne reči
|
1332
|
setting_commit_fix_keywords: Fiksne ključne reči
|
1333
|
setting_autologin: Automatsko prijavljivanje
|
1334
|
diff --git a/lang/sv.yml b/lang/sv.yml
|
1335
|
index 852c7fe..29a80e4 100644
|
1336
|
--- a/lang/sv.yml
|
1337
|
+++ b/lang/sv.yml
|
1338
|
@@ -106,6 +106,8 @@ field_is_required: Obligatorisk
|
1339
|
field_firstname: Förnamn
|
1340
|
field_lastname: Efternamn
|
1341
|
field_mail: Mail
|
1342
|
+field_ssh_key: SSH Public Key
|
1343
|
+field_ssh_key_type: SSH Public Key Type
|
1344
|
field_filename: Fil
|
1345
|
field_filesize: Storlek
|
1346
|
field_downloads: Nerladdningar
|
1347
|
@@ -203,6 +205,7 @@ setting_feeds_limit: Innehållsgräns för Feed
|
1348
|
setting_default_projects_public: Nya projekt är publika som standard
|
1349
|
setting_autofetch_changesets: Automatisk hämtning av commits
|
1350
|
setting_sys_api_enabled: Aktivera WS för repository-hantering
|
1351
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1352
|
setting_commit_ref_keywords: Referens-nyckelord
|
1353
|
setting_commit_fix_keywords: Fix-nyckelord
|
1354
|
setting_autologin: Automatisk inloggning
|
1355
|
diff --git a/lang/th.yml b/lang/th.yml
|
1356
|
index c0a3859..e8d93f1 100644
|
1357
|
--- a/lang/th.yml
|
1358
|
+++ b/lang/th.yml
|
1359
|
@@ -103,6 +103,8 @@ field_is_required: ต้องใส่
|
1360
|
field_firstname: ชื่อ
|
1361
|
field_lastname: นามสกุล
|
1362
|
field_mail: อีเมล์
|
1363
|
+field_ssh_key: SSH Public Key
|
1364
|
+field_ssh_key_type: SSH Public Key Type
|
1365
|
field_filename: แฟ้ม
|
1366
|
field_filesize: ขนาด
|
1367
|
field_downloads: ดาวน์โหลด
|
1368
|
@@ -198,6 +200,7 @@ setting_feeds_limit: จำนวน Feed
|
1369
|
setting_default_projects_public: โครงการใหม่มีค่าเริ่มต้นเป็น สาธารณะ
|
1370
|
setting_autofetch_changesets: ดึง commits อัตโนมัติ
|
1371
|
setting_sys_api_enabled: เปิดใช้ WS สำหรับการจัดการที่เก็บต้นฉบับ
|
1372
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1373
|
setting_commit_ref_keywords: คำสำคัญ Referencing
|
1374
|
setting_commit_fix_keywords: คำสำคัญ Fixing
|
1375
|
setting_autologin: เข้าระบบอัตโนมัติ
|
1376
|
diff --git a/lang/tr.yml b/lang/tr.yml
|
1377
|
index 8136367..1bb9eb3 100644
|
1378
|
--- a/lang/tr.yml
|
1379
|
+++ b/lang/tr.yml
|
1380
|
@@ -102,6 +102,8 @@ field_is_required: Gerekli
|
1381
|
field_firstname: Ad
|
1382
|
field_lastname: Soyad
|
1383
|
field_mail: E-Posta
|
1384
|
+field_ssh_key: SSH Public Key
|
1385
|
+field_ssh_key_type: SSH Public Key Type
|
1386
|
field_filename: Dosya
|
1387
|
field_filesize: Boyut
|
1388
|
field_downloads: İndirilenler
|
1389
|
@@ -197,6 +199,7 @@ setting_feeds_limit: Haber yayını içerik limiti
|
1390
|
setting_default_projects_public: Yeni projeler varsayılan olarak herkese açık
|
1391
|
setting_autofetch_changesets: Otomatik gönderi al
|
1392
|
setting_sys_api_enabled: Depo yönetimi için WS'yi etkinleştir
|
1393
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1394
|
setting_commit_ref_keywords: Başvuru Kelimeleri
|
1395
|
setting_commit_fix_keywords: Sabitleme kelimeleri
|
1396
|
setting_autologin: Otomatik Giriş
|
1397
|
diff --git a/lang/uk.yml b/lang/uk.yml
|
1398
|
index be121cb..3a5840e 100644
|
1399
|
--- a/lang/uk.yml
|
1400
|
+++ b/lang/uk.yml
|
1401
|
@@ -97,6 +97,8 @@ field_is_required: Необхідно
|
1402
|
field_firstname: Ім'я
|
1403
|
field_lastname: Прізвище
|
1404
|
field_mail: Ел. пошта
|
1405
|
+field_ssh_key: SSH Public Key
|
1406
|
+field_ssh_key_type: SSH Public Key Type
|
1407
|
field_filename: Файл
|
1408
|
field_filesize: Розмір
|
1409
|
field_downloads: Завантаження
|
1410
|
@@ -189,6 +191,7 @@ setting_wiki_compression: Стиснення історії Wiki
|
1411
|
setting_feeds_limit: Обмеження змісту подачі
|
1412
|
setting_autofetch_changesets: Автоматично доставати доповнення
|
1413
|
setting_sys_api_enabled: Дозволити WS для управління репозиторієм
|
1414
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1415
|
setting_commit_ref_keywords: Ключові слова для посилання
|
1416
|
setting_commit_fix_keywords: Призначення ключових слів
|
1417
|
setting_autologin: Автоматичний вхід
|
1418
|
diff --git a/lang/vn.yml b/lang/vn.yml
|
1419
|
index 908e232..24b800f 100644
|
1420
|
--- a/lang/vn.yml
|
1421
|
+++ b/lang/vn.yml
|
1422
|
@@ -106,6 +106,8 @@ field_is_required: Bắt buộc
|
1423
|
field_firstname: Tên lót + Tên
|
1424
|
field_lastname: Họ
|
1425
|
field_mail: Email
|
1426
|
+field_ssh_key: SSH Public Key
|
1427
|
+field_ssh_key_type: SSH Public Key Type
|
1428
|
field_filename: Tập tin
|
1429
|
field_filesize: Cỡ
|
1430
|
field_downloads: Tải về
|
1431
|
@@ -202,6 +204,7 @@ setting_feeds_limit: Giới hạn nội dung của feed
|
1432
|
setting_default_projects_public: Dự án mặc định là công cộng
|
1433
|
setting_autofetch_changesets: Autofetch commits
|
1434
|
setting_sys_api_enabled: Enable WS for repository management
|
1435
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1436
|
setting_commit_ref_keywords: Từ khóa tham khảo
|
1437
|
setting_commit_fix_keywords: Từ khóa chỉ vấn đề đã giải quyết
|
1438
|
setting_autologin: Tự động đăng nhập
|
1439
|
diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml
|
1440
|
index 50eccf4..5ccd4a0 100644
|
1441
|
--- a/lang/zh-tw.yml
|
1442
|
+++ b/lang/zh-tw.yml
|
1443
|
@@ -106,6 +106,8 @@ field_is_required: 必填
|
1444
|
field_firstname: 名字
|
1445
|
field_lastname: 姓氏
|
1446
|
field_mail: 電子郵件
|
1447
|
+field_ssh_key: SSH Public Key
|
1448
|
+field_ssh_key_type: SSH Public Key Type
|
1449
|
field_filename: 檔案名稱
|
1450
|
field_filesize: 大小
|
1451
|
field_downloads: 下載次數
|
1452
|
@@ -203,6 +205,7 @@ setting_feeds_limit: RSS 新聞限制
|
1453
|
setting_autofetch_changesets: 自動取得送交版次
|
1454
|
setting_default_projects_public: 新建立之專案預設為「公開」
|
1455
|
setting_sys_api_enabled: 啟用管理版本庫之網頁服務 (Web Service)
|
1456
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1457
|
setting_commit_ref_keywords: 送交用於參照項目之關鍵字
|
1458
|
setting_commit_fix_keywords: 送交用於修正項目之關鍵字
|
1459
|
setting_autologin: 自動登入
|
1460
|
diff --git a/lang/zh.yml b/lang/zh.yml
|
1461
|
index 989f329..32f889b 100644
|
1462
|
--- a/lang/zh.yml
|
1463
|
+++ b/lang/zh.yml
|
1464
|
@@ -106,6 +106,8 @@ field_is_required: 必填
|
1465
|
field_firstname: 名字
|
1466
|
field_lastname: 姓氏
|
1467
|
field_mail: 邮件地址
|
1468
|
+field_ssh_key: SSH Public Key
|
1469
|
+field_ssh_key_type: SSH Public Key Type
|
1470
|
field_filename: 文件
|
1471
|
field_filesize: 大小
|
1472
|
field_downloads: 下载次数
|
1473
|
@@ -203,6 +205,7 @@ setting_feeds_limit: RSS Feed内容条数限制
|
1474
|
setting_default_projects_public: 新建项目默认为公开项目
|
1475
|
setting_autofetch_changesets: 自动获取程序变更
|
1476
|
setting_sys_api_enabled: 启用用于版本库管理的Web Service
|
1477
|
+setting_serve_git_repositories: Serve GIT repositories using Redmine's SSH account
|
1478
|
setting_commit_ref_keywords: 用于引用问题的关键字
|
1479
|
setting_commit_fix_keywords: 用于解决问题的关键字
|
1480
|
setting_autologin: 自动登录
|
1481
|
diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb
|
1482
|
index a9e1dda..77dd6ca 100644
|
1483
|
--- a/lib/redmine/scm/adapters/git_adapter.rb
|
1484
|
+++ b/lib/redmine/scm/adapters/git_adapter.rb
|
1485
|
@@ -24,6 +24,25 @@ module Redmine
|
1486
|
|
1487
|
# Git executable name
|
1488
|
GIT_BIN = "git"
|
1489
|
+ EMPTY_COMMIT = "0000000000000000000000000000000000000000"
|
1490
|
+
|
1491
|
+ def init(description)
|
1492
|
+ FileUtils.mkdir_p "#{url}"
|
1493
|
+ cmd = "#{GIT_BIN} --git-dir #{target('')} init --template=#{RAILS_ROOT}/lib/redmine/scm/adapters/git_templates --bare"
|
1494
|
+ shellout(cmd)
|
1495
|
+ Dir["#{url}/**/*"].each do |file|
|
1496
|
+ if File.file?(file)
|
1497
|
+ File.open(file, "r") do |source|
|
1498
|
+ File.open(file + ".new", "w", File.stat(file).mode) do |dest|
|
1499
|
+ source.each_line do |line|
|
1500
|
+ dest << line.gsub('#{description}', description).gsub('#{RAILS_ROOT}', RAILS_ROOT).gsub('#{RAILS_ENV}', ENV["RAILS_ENV"])
|
1501
|
+ end
|
1502
|
+ end
|
1503
|
+ end
|
1504
|
+ FileUtils.mv file + ".new", file
|
1505
|
+ end
|
1506
|
+ end
|
1507
|
+ end
|
1508
|
|
1509
|
# Get the revision of a particuliar file
|
1510
|
def get_rev (rev,path)
|
1511
|
@@ -61,7 +80,7 @@ module Redmine
|
1512
|
elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
|
1513
|
key = $1
|
1514
|
value = $2
|
1515
|
- if key == "Author"
|
1516
|
+ if key == "Commit"
|
1517
|
changeset[:author] = value
|
1518
|
elsif key == "CommitDate"
|
1519
|
changeset[:date] = value
|
1520
|
@@ -140,7 +159,7 @@ module Redmine
|
1521
|
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
|
1522
|
cmd << " --reverse" if options[:reverse]
|
1523
|
cmd << " -n #{options[:limit].to_i} " if (!options.nil?) && options[:limit]
|
1524
|
- cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
|
1525
|
+ cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from and identifier_from != EMPTY_COMMIT
|
1526
|
cmd << " #{shell_quote identifier_to} " if identifier_to
|
1527
|
shellout(cmd) do |io|
|
1528
|
files=[]
|
1529
|
@@ -262,6 +281,21 @@ module Redmine
|
1530
|
return nil if $? && $?.exitstatus != 0
|
1531
|
cat
|
1532
|
end
|
1533
|
+
|
1534
|
+ def get_object_type(object)
|
1535
|
+ cmd = "#{GIT_BIN} --git-dir #{target('')} cat-file -t #{object}"
|
1536
|
+ type = ""
|
1537
|
+ GitAdapter.shellout(cmd) do |io|
|
1538
|
+ return io.read.strip
|
1539
|
+ end
|
1540
|
+ end
|
1541
|
+
|
1542
|
+ def merge_base(old_rev, new_rev)
|
1543
|
+ cmd = "#{GIT_BIN} --git-dir #{target('')} merge-base #{old_rev} #{new_rev}"
|
1544
|
+ GitAdapter.shellout(cmd) do |io|
|
1545
|
+ return io.read.strip
|
1546
|
+ end
|
1547
|
+ end
|
1548
|
end
|
1549
|
end
|
1550
|
end
|
1551
|
diff --git a/lib/redmine/scm/adapters/git_templates/description b/lib/redmine/scm/adapters/git_templates/description
|
1552
|
new file mode 100644
|
1553
|
index 0000000..b0f81f9
|
1554
|
--- /dev/null
|
1555
|
+++ b/lib/redmine/scm/adapters/git_templates/description
|
1556
|
@@ -0,0 +1 @@
|
1557
|
+#{description}
|
1558
|
\ No newline at end of file
|
1559
|
diff --git a/lib/redmine/scm/adapters/git_templates/hooks/post-receive b/lib/redmine/scm/adapters/git_templates/hooks/post-receive
|
1560
|
new file mode 100755
|
1561
|
index 0000000..d9a4b23
|
1562
|
--- /dev/null
|
1563
|
+++ b/lib/redmine/scm/adapters/git_templates/hooks/post-receive
|
1564
|
@@ -0,0 +1 @@
|
1565
|
+ruby #{RAILS_ROOT}/script/runner Repository.fetch_changesets -e #{RAILS_ENV}
|
1566
|
\ No newline at end of file
|
1567
|
diff --git a/lib/redmine/scm/adapters/git_templates/hooks/pre-receive b/lib/redmine/scm/adapters/git_templates/hooks/pre-receive
|
1568
|
new file mode 100755
|
1569
|
index 0000000..6956009
|
1570
|
--- /dev/null
|
1571
|
+++ b/lib/redmine/scm/adapters/git_templates/hooks/pre-receive
|
1572
|
@@ -0,0 +1 @@
|
1573
|
+ruby #{RAILS_ROOT}/script/runner GitManager.check_commits -e #{RAILS_ENV}
|
1574
|
\ No newline at end of file
|
1575
|
diff --git a/lib/redmine/scm/adapters/git_templates/info/exclude b/lib/redmine/scm/adapters/git_templates/info/exclude
|
1576
|
new file mode 100644
|
1577
|
index 0000000..2c87b72
|
1578
|
--- /dev/null
|
1579
|
+++ b/lib/redmine/scm/adapters/git_templates/info/exclude
|
1580
|
@@ -0,0 +1,6 @@
|
1581
|
+# git-ls-files --others --exclude-from=.git/info/exclude
|
1582
|
+# Lines that start with '#' are comments.
|
1583
|
+# For a project mostly in C, the following would be a good set of
|
1584
|
+# exclude patterns (uncomment them if you want to use them):
|
1585
|
+# *.[oa]
|
1586
|
+# *~
|
1587
|
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
|
1588
|
index 2e60ee4..c3b66f5 100644
|
1589
|
--- a/public/stylesheets/application.css
|
1590
|
+++ b/public/stylesheets/application.css
|
1591
|
@@ -240,7 +240,7 @@ ul.properties li span {font-style:italic;}
|
1592
|
.total-hours span.hours-int { font-size: 120%; }
|
1593
|
|
1594
|
.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}
|
1595
|
-#user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }
|
1596
|
+#user_firstname, #user_lastname, #user_mail, #user_ssh_key, #my_account_form select { width: 90%; }
|
1597
|
|
1598
|
.pagination {font-size: 90%}
|
1599
|
p.pagination {margin-top:8px;}
|
1600
|
diff --git a/test/unit/authorized_keys_entry_test.rb b/test/unit/authorized_keys_entry_test.rb
|
1601
|
new file mode 100644
|
1602
|
index 0000000..8297091
|
1603
|
--- /dev/null
|
1604
|
+++ b/test/unit/authorized_keys_entry_test.rb
|
1605
|
@@ -0,0 +1,52 @@
|
1606
|
+require File.dirname(__FILE__) + '/../test_helper'
|
1607
|
+
|
1608
|
+class AuthorizedKeysEntryTest < Test::Unit::TestCase
|
1609
|
+ def setup
|
1610
|
+ AuthorizedKeysEntry.authorized_keys_filename = File.dirname(__FILE__) + '/../../tmp/test/authorized_keys'
|
1611
|
+ e = AuthorizedKeysEntry.new
|
1612
|
+ e.identifier = 'admin'
|
1613
|
+ e.key = 'ssh-dss AAAAB3NzaC1kc3MAAACBALDC8OcQ6OfKUMUEy4xeARLmIGMB6IH4GpSQPTAIpMkRvmyIc99NiRVl1TSlASQQephL0XSH6R2vP+XEzY/tSGIzGugyIkErV2AZ8JL/BwZI1euVE3tjBDoL+6xpdqMCgUwWh2vrL/Qe8DOoil2nTtnHJBTz0wpkYHe+DDKda7ttAAAAFQDZ13q/5MPUvT9AjyeUvWZe2lFC/QAAAIAikSLreTOTeDjKkSrRrhV2RByfT5wyat/0rulzU9wp6KOre9XtH5VNhlGAz0Sj5MgoxUJuHrlIjSNoxnx9S3h1TKHaZ2Ov5xKc4AtfnmH5LwyXdT9QzbsB1NL4xDAjBPHGQCEypxRVz3zLp9gt6gCzBszbS563pIfUmqikaI9iwgAAAIA8/GFBKSn0E4kFsWRSiUeRyEeXBKPbghMcFePOp/v23xZrNGTso6AKCXPMvLcVZbpiZY4wIL0nftYdQNcu3ubDIKWVKIfdisWpKxgejbKQZMQWQRPZZVxT/UtkPuF4mjJyynbdc0Fn78gxfySnmpvfoGhVMJYd+Xjjagr4sU8Hpw== sadf@sdfsd.kdl.sdfoij'
|
1614
|
+ e.type = 'ssh-dss'
|
1615
|
+ e.options = [ 'command="test"' ]
|
1616
|
+
|
1617
|
+ e.save
|
1618
|
+ end
|
1619
|
+
|
1620
|
+ def test_read
|
1621
|
+ e = AuthorizedKeysEntry.find_by_identifier('admin')
|
1622
|
+ assert e.key =~ /\AAAAAB3NzaC1kc3/
|
1623
|
+ assert e.type == 'ssh-dss'
|
1624
|
+ assert e.options.kind_of?(Array)
|
1625
|
+ end
|
1626
|
+
|
1627
|
+ def test_verify_wrong
|
1628
|
+ e = AuthorizedKeysEntry.new
|
1629
|
+ e.identifier = 'a'
|
1630
|
+ e.key = 'b'
|
1631
|
+ e.type = 'ssh-dss'
|
1632
|
+ e.options = []
|
1633
|
+ assert !e.validate
|
1634
|
+ end
|
1635
|
+
|
1636
|
+ def test_replace
|
1637
|
+ e = AuthorizedKeysEntry.new
|
1638
|
+ e.identifier = 'admin'
|
1639
|
+ e.key = 'AAAAB3NzaC1yc2EAAAABIwAAAEEAsUX/IBulIRL9y49x5AEuXad+nDmGTY1Ad+c2YFJPMQgJWtY+cDUrUNDBxyvYADDzFldeNMDAwAeBFSfQL8h3ew=='
|
1640
|
+ e.type = 'ssh-rsa'
|
1641
|
+ e.save
|
1642
|
+
|
1643
|
+ assert AuthorizedKeysEntry.find_by_identifier('admin').type = 'ssh-rsa'
|
1644
|
+ end
|
1645
|
+
|
1646
|
+ def test_delete
|
1647
|
+ e = AuthorizedKeysEntry.new
|
1648
|
+ e.identifier = 'admin'
|
1649
|
+ e.key = ''
|
1650
|
+ e.type = ''
|
1651
|
+ e.options = []
|
1652
|
+ e.save
|
1653
|
+
|
1654
|
+ assert AuthorizedKeysEntry.find_by_identifier('admin') == nil
|
1655
|
+ end
|
1656
|
+end
|
1657
|
+
|
1658
|
--
|
1659
|
1.6.1.3
|
1660
|
|