10 | <% form_tag url_for(:controller => 'deployment_credentials', :action => 'destroy', :project_id => @project, :id => @cred.id ), :method => :delete do %>
11 |
17 |
--------------------------------------------------------------------------------
/app/views/repositories/edit.html.erb:
--------------------------------------------------------------------------------
1 |
<%= l(:label_repository) %>
2 |
3 | <% labelled_form_for :repository, @repository, :url => repository_path(@path), :html => {:method => :put} do |f| %>
4 | <%= render :partial => 'form', :locals => {:f => f} %>
5 | <% end %>
6 |
7 |
8 | <% if @repository && @repository.is_a?(Repository::Git) && !(@repository.nil? || @repository.new_record?) %>
9 | <% if GitHostingHelper.can_view_deployment_keys(@repository.project) %>
10 | <%= render :partial => 'deployment_credentials/view_list' %>
11 | <% end %>
12 |
13 | <% if GitHostingHelper.can_view_post_receive_urls(@repository.project) %>
14 | <%= render :partial => 'repository_post_receive_urls/view_list' %>
15 | <% end %>
16 |
17 | <% if GitHostingHelper.can_view_mirrors(@repository.project) %>
18 | <%= render :partial => 'repository_mirrors/view_list' %>
19 | <% end %>
20 | <% end %>
21 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/sys_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'sys_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module SysControllerPatch
9 | def fetch_changesets_with_disable_update
10 | # Turn of updates during repository update
11 | GitHostingObserver.set_update_active(false);
12 |
13 | # Do actual update
14 | fetch_changesets_without_disable_update
15 |
16 | # Perform the updating process on all projects
17 | GitHostingObserver.set_update_active(:resync_all);
18 | end
19 |
20 | def self.included(base)
21 | base.class_eval do
22 | unloadable
23 | end
24 | begin
25 | base.send(:alias_method_chain, :fetch_changesets, :disable_update)
26 | rescue
27 | end
28 | end
29 | end
30 | end
31 | end
32 |
33 | # Patch in changes
34 | SysController.send(:include, GitHosting::Patches::SysControllerPatch)
35 |
--------------------------------------------------------------------------------
/app/views/cia_notification_mailer/cia_notification.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= @plugin.name %>
4 | <%= @plugin.version %>
5 | <%= @plugin.url %>
6 |
7 |
8 | <%= @revision.project.name %>
9 | <%= @branch %>
10 |
11 | <%= @revision.committed_on.to_i %>
12 |
13 |
14 | <%= @revision.revision[0..10] %>
15 | <%= @revision.author %>
16 | <%= @revision.comments %>
17 | <%= url_for_revision(@revision) %>
18 | <%- if not @revision.changes.empty? -%>
19 |
20 | <%- @revision.changes.each do |change| -%>
21 | <%= change.path %>
22 | <%- end -%>
23 |
24 | <%- end -%>
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/views/repository_mirrors/push.html.erb:
--------------------------------------------------------------------------------
1 | <% if not @is_xhr -%>
2 | <%= stylesheet_link_tag('application', :plugin => 'redmine_git_hosting') %>
3 |
<%=l(:button_push_title)%>
4 | <%- end %>
5 |
6 | <%= l(:mirror_push_info_html, :mirror_url => @mirror.url, :status => @push_failed==true ? l(:mirror_push_fail) : l(:mirror_push_sucess)) %>
7 |
8 |
<%= l(:mirror_push_output_label) %>
9 |
"><%= @shellout %>
10 | <% if @is_xhr && @push_failed==false -%>
11 |
26 | <%- end %>
27 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/groups_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'groups_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module GroupsControllerPatch
9 |
10 | @@original_projects = []
11 |
12 | def disable_git_observer_updates
13 | GitHostingObserver.set_update_active(false)
14 | end
15 |
16 | def do_single_update
17 | GitHostingObserver.set_update_active(true)
18 | end
19 |
20 |
21 | def self.included(base)
22 | base.class_eval do
23 | unloadable
24 | end
25 | base.send(:before_filter, :disable_git_observer_updates, :only=>[:update, :destroy, :add_users, :remove_user, :edit_membership, :destroy_membership])
26 | base.send(:after_filter, :do_single_update, :only=>[:update, :destroy, :add_users, :remove_user, :edit_membership, :destroy_membership])
27 | end
28 | end
29 | end
30 | end
31 |
32 | # Patch in changes
33 | GroupsController.send(:include, GitHosting::Patches::GroupsControllerPatch)
34 |
--------------------------------------------------------------------------------
/assets/javascripts/zero_clipboard_setup.js:
--------------------------------------------------------------------------------
1 | var zero_clipboard_source_input_control_id = "git_url_text";
2 | var clipboard = null
3 |
4 | function reset_zero_clipboard()
5 | {
6 | var clip_container = $('clipboard_container');
7 | if (clip_container) {
8 | clip_container.show();
9 | clip_container.style.fontFamily="serif"
10 |
11 | var cur_children = clip_container.childNodes;
12 | var ci;
13 | for(ci=0; ci< cur_children.length; ci++)
14 | {
15 | var c = cur_children[ci];
16 | if(c.id != "clipboard_button")
17 | {
18 | clip_container.removeChild(c);
19 | }
20 | }
21 |
22 | clipboard = new ZeroClipboard.Client();
23 |
24 | clipboard.setHandCursor(true);
25 | clipboard.glue('clipboard_button', 'clipboard_container');
26 |
27 | clipboard.addEventListener('mouseOver', function (client) {
28 | clipboard.setText($(zero_clipboard_source_input_control_id).value);
29 | });
30 | }
31 | }
32 |
33 | function setZeroClipboardInputSource(id)
34 | {
35 | zero_clipboard_source_input_control_id = id;
36 | }
37 |
38 | document.observe("dom:loaded", function() { reset_zero_clipboard(); } )
39 |
--------------------------------------------------------------------------------
/db/migrate/20120708070841_add_settings_to_plugin_4.rb:
--------------------------------------------------------------------------------
1 | class AddSettingsToPlugin4 < ActiveRecord::Migration
2 | def self.up
3 | begin
4 | # Add some new settings to settings page, if they don't exist
5 | valuehash = (Setting.plugin_redmine_git_hosting).clone
6 | valuehash['gitForceHooksUpdate'] ||= 'true'
7 | if (Setting.plugin_redmine_git_hosting != valuehash)
8 | say "Added redmine_git_hosting settings: 'gitForceHooksUpdate'."
9 | Setting.plugin_redmine_git_hosting = valuehash
10 | end
11 | rescue => e
12 | # ignore problems if plugin settings don't exist yet
13 | end
14 | end
15 |
16 | def self.down
17 | begin
18 | # Remove above settings from plugin page
19 | valuehash = (Setting.plugin_redmine_git_hosting).clone
20 | valuehash.delete('gitForceHooksUpdate')
21 |
22 | if (Setting.plugin_redmine_git_hosting != valuehash)
23 | say "Removed redmine_git_hosting settings: 'gitForceHooksUpdate'."
24 | Setting.plugin_redmine_git_hosting = valuehash
25 | end
26 | rescue => e
27 | # ignore problems if table doesn't exist yet....
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/app/views/layouts/popup.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= begin csrf_meta_tag; rescue; "" end %>
8 | <%= favicon %>
9 | <%= stylesheet_link_tag 'application', :media => 'all' %>
10 | <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
11 | <%= defined?(javascript_heads)? javascript_heads : javascript_include_tag(:defaults) %>
12 | <%= heads_for_theme %>
13 |
19 | <%= call_hook :view_layouts_base_html_head %>
20 |
21 |
22 | <%= render_flash_messages %>
23 | <%= yield %>
24 |
25 |
26 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/repository_cia_filters.rb:
--------------------------------------------------------------------------------
1 | module GitHosting
2 | module Patches
3 | module RepositoryCiaFilters
4 | module FilterMethods
5 | def notified(scmid)
6 | scmid = scmid.scmid if scmid.instance_of?(Changeset)
7 | #self.cia_notifications.push GitCiaNotification.new(:scmid => scmid)
8 | self.push GitCiaNotification.new(:scmid => scmid)
9 | end
10 |
11 | def notified?(scmid)
12 | #GitHosting.logger.debug "1On has_notified? processing smcid: #{scmid}"
13 | scmid = scmid.scmid if scmid.instance_of?(Changeset)
14 | #GitHosting.logger.debug "2On has_notified? processing smcid: #{scmid}"
15 | #q = find(:first, :conditions => ["scmid = ?", scmid])
16 | #GitHosting.logger.debug "Query result: #{q}, NIL? #{q.nil?}"
17 | #return !q.nil?
18 | #return !self.cia_notifications.find(:first, :conditions => ["scmid = ?", scmid_]).nil?
19 | return !find(:first, :conditions => ["scmid = ?", scmid]).nil?
20 | end
21 | end
22 | def self.included(base)
23 | base.class_eval do
24 | unloadable
25 | end
26 | base.extend(FilterMethods)
27 | end
28 | end
29 | end
30 | end
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/helpers/gitolite_public_keys_helper.rb:
--------------------------------------------------------------------------------
1 | module GitolitePublicKeysHelper
2 | def gitolite_public_keys_status_options_for_select(user, selected)
3 | key_count_by_active = user.gitolite_public_keys.count(:group => 'active').to_hash
4 | options_for_select([[l(:label_all), nil],
5 | ["#{l(:status_active)} (#{key_count_by_active[true].to_i})", GitolitePublicKey::STATUS_ACTIVE],
6 | ["#{l(:status_locked)} (#{key_count_by_active[false].to_i})", GitolitePublicKey::STATUS_LOCKED]], selected)
7 | end
8 |
9 | def keylabel(key)
10 | if key.user == User.current
11 | "\"#{key.title}\""
12 | else
13 | "\"#{key.user.login}@#{key.title}\""
14 | end
15 | end
16 |
17 | def keylabel_text(key)
18 | if key.user == User.current
19 | "#{key.title}"
20 | else
21 | "#{key.user.login}@#{key.title}"
22 | end
23 | end
24 |
25 | def wrap_and_join(in_array,my_or="or")
26 | my_array = in_array.map{|x| "\"#{x}\""}
27 | length = my_array.length
28 | return my_array if length < 2
29 | my_array[length-1] = my_or+" "+my_array[length-1]
30 | if length == 2
31 | my_array.join(' ')
32 | else
33 | my_array.join(', ')
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/selinux/redmine_git.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | DIRNAME=`dirname $0`
4 | cd $DIRNAME
5 | USAGE="$0 [ --update ]"
6 | if [ `id -u` != 0 ]; then
7 | echo 'You must be root to run this script'
8 | exit 1
9 | fi
10 |
11 | if [ $# -eq 1 ]; then
12 | if [ "$1" = "--update" ] ; then
13 | time=`ls -l --time-style="+%x %X" redmine_git.te | awk '{ printf "%s %s", $6, $7 }'`
14 | rules=`ausearch --start $time -m avc --raw -se redmine_git`
15 | if [ x"$rules" != "x" ] ; then
16 | echo "Found avc's to update policy with"
17 | echo -e "$rules" | audit2allow -R
18 | echo "Do you want these changes added to policy [y/n]?"
19 | read ANS
20 | if [ "$ANS" = "y" -o "$ANS" = "Y" ] ; then
21 | echo "Updating policy"
22 | echo -e "$rules" | audit2allow -R >> redmine_git.te
23 | # Fall though and rebuild policy
24 | else
25 | exit 0
26 | fi
27 | else
28 | echo "No new avcs found"
29 | exit 0
30 | fi
31 | else
32 | echo -e $USAGE
33 | exit 1
34 | fi
35 | elif [ $# -ge 2 ] ; then
36 | echo -e $USAGE
37 | exit 1
38 | fi
39 |
40 | echo "Building and Loading Policy"
41 | set -x
42 | make -f /usr/share/selinux/devel/Makefile
43 | /usr/sbin/semodule -i redmine_git.pp
44 |
45 |
--------------------------------------------------------------------------------
/app/models/repository_post_receive_url.rb:
--------------------------------------------------------------------------------
1 | class RepositoryPostReceiveUrl < ActiveRecord::Base
2 | STATUS_ACTIVE = 1
3 | STATUS_INACTIVE = 0
4 |
5 | belongs_to :repository
6 |
7 | attr_accessible :url, :mode, :active
8 |
9 | validates_uniqueness_of :url, :scope => [:repository_id]
10 | validates_presence_of :repository_id
11 | validates_format_of :url, :with => URI::regexp(%w(http https))
12 | validates_associated :repository
13 |
14 | before_validation :strip_whitespace
15 |
16 | named_scope :active, {:conditions => {:active => RepositoryPostReceiveUrl::STATUS_ACTIVE}}
17 | named_scope :inactive, {:conditions => {:active => RepositoryPostReceiveUrl::STATUS_INACTIVE}}
18 |
19 | validates_inclusion_of :mode, :in => [:github, :get]
20 | def mode
21 | read_attribute(:mode).to_sym rescue nil
22 | end
23 | def mode= (value)
24 | write_attribute(:mode, (value.to_sym && value.to_sym.to_s rescue nil))
25 | end
26 |
27 | def to_s
28 | return File.join("#{repository.project.identifier}-#{url}")
29 | end
30 |
31 | protected
32 |
33 | # Strip leading and trailing whitespace
34 | def strip_whitespace
35 | self.url = url.strip
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/app/views/settings/_display_access.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
<%= l(:label_current_access_patterns) %>
3 | <%= l(:display_access_setup, :type => (GitHosting.multi_repos? ? "default " : "")) %>:
4 |
5 | Repo Storage:
6 | <%= "~#{@settings['gitUser']}/#{@settings['gitRepositoryBasePath']}#{@settings['gitRedmineSubdir']}#{(GitHosting.repository_hierarchy)?'project1/project2/':''}project3.git "
7 | %>
8 |
9 | <%= l(:label_ssh_access)%>:
10 | <% gitSHP = Setting.plugin_redmine_git_hosting['gitServer'].match(/:\d+$/) %>
11 | <%= "#{gitSHP ? 'ssh://' : ''}#{@settings['gitUser']}@#{@settings['gitServer']}#{gitSHP ? '/' : ':'}#{@settings['gitRedmineSubdir']}#{(GitHosting.repository_hierarchy)?'project1/project2/':''}project3.git "
12 | %>
13 |
14 | <%= l(:label_http_access)%>:
15 | <%= "http://redmine-user @#{GitHosting.my_root_url}/#{GitHosting.http_server_subdir}#{(GitHosting.repository_hierarchy)?'project1/project2/':''}project3.git "
16 | %>
17 |
18 | <%= l(:display_access_emphasis) %>
19 | <%= @settings['gitRepositoryHierarchy']=='true' ? l(:display_access_hierarchical) : l(:display_access_flat) %>
20 |
21 |
--------------------------------------------------------------------------------
/db/migrate/20120724211806_add_settings_to_plugin_5.rb:
--------------------------------------------------------------------------------
1 | class AddSettingsToPlugin5 < ActiveRecord::Migration
2 | def self.up
3 | begin
4 | # Add some new settings to settings page, if they don't exist
5 | valuehash = (Setting.plugin_redmine_git_hosting).clone
6 | valuehash['gitConfigFile'] ||= 'gitolite.conf'
7 | valuehash['gitConfigHasAdminKey'] ||= 'true'
8 |
9 | if (Setting.plugin_redmine_git_hosting != valuehash)
10 | say "Added redmine_git_hosting settings: 'gitConfigFile', 'gitConfigHasAdminKey'"
11 | Setting.plugin_redmine_git_hosting = valuehash
12 | end
13 | rescue => e
14 | # ignore problems if plugin settings don't exist yet
15 | end
16 | end
17 |
18 | def self.down
19 | begin
20 | # Remove above settings from plugin page
21 | valuehash = (Setting.plugin_redmine_git_hosting).clone
22 | valuehash.delete('gitConfigFile')
23 | valuehash.delete('gitConfigHasAdminKey')
24 |
25 | if (Setting.plugin_redmine_git_hosting != valuehash)
26 | say "Removed redmine_git_hosting settings: 'gitConfigFile', 'gitConfigHasAdminKey"
27 | Setting.plugin_redmine_git_hosting = valuehash
28 | end
29 | rescue => e
30 | # ignore problems if table doesn't exist yet....
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/db/migrate/20091119162426_set_mirror_role_permissions.rb:
--------------------------------------------------------------------------------
1 | class SetMirrorRolePermissions < ActiveRecord::Migration
2 | def self.up
3 |
4 | begin
5 | GitHostingObserver.set_update_active(false)
6 |
7 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
8 | manager_role.add_permission! :view_repository_mirrors
9 | manager_role.add_permission! :edit_repository_mirrors
10 | manager_role.add_permission! :create_repository_mirrors
11 | manager_role.save
12 |
13 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
14 | developer_role.add_permission! :view_repository_mirrors
15 | developer_role.save
16 | rescue
17 | end
18 |
19 | end
20 |
21 | def self.down
22 |
23 | begin
24 | GitHostingObserver.set_update_active(false)
25 |
26 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
27 | manager_role.remove_permission! :view_repository_mirrors
28 | manager_role.remove_permission! :edit_repository_mirrors
29 | manager_role.remove_permission! :create_repository_mirrors
30 | manager_role.save
31 |
32 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
33 | developer_role.remove_permission! :view_repository_mirrors
34 | developer_role.save
35 | rescue
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/db/migrate/2012052100001_set_post_receive_url_role_permissions.rb:
--------------------------------------------------------------------------------
1 | class SetPostReceiveUrlRolePermissions < ActiveRecord::Migration
2 | def self.up
3 |
4 | begin
5 | GitHostingObserver.set_update_active(false)
6 |
7 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
8 | manager_role.add_permission! :view_repository_post_receive_urls
9 | manager_role.add_permission! :edit_repository_post_receive_urls
10 | manager_role.add_permission! :create_repository_post_receive_urls
11 | manager_role.save
12 |
13 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
14 | developer_role.add_permission! :view_repository_post_receive_urls
15 | developer_role.save
16 | rescue
17 | end
18 |
19 | end
20 |
21 | def self.down
22 |
23 | begin
24 | GitHostingObserver.set_update_active(false)
25 |
26 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
27 | manager_role.remove_permission! :view_repository_post_receive_urls
28 | manager_role.remove_permission! :edit_repository_post_receive_urls
29 | manager_role.remove_permission! :create_repository_post_receive_urls
30 | manager_role.save
31 |
32 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
33 | developer_role.remove_permission! :view_repository_post_receive_urls
34 | developer_role.save
35 | rescue
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/db/migrate/20111123214911_add_settings_to_plugin.rb:
--------------------------------------------------------------------------------
1 | class AddSettingsToPlugin < ActiveRecord::Migration
2 | def self.up
3 | begin
4 | # Add some new settings to settings page, if they don't exist
5 | valuehash = (Setting.plugin_redmine_git_hosting).clone
6 | valuehash['gitRecycleBasePath'] ||= 'recycle_bin/'
7 | valuehash['gitRecycleExpireTime'] ||= '24.0'
8 | valuehash['gitLockWaitTime'] ||= '10'
9 | if (Setting.plugin_redmine_git_hosting != valuehash)
10 | Setting.plugin_redmine_git_hosting = valuehash
11 | say "Added redmine_git_hosting settings: 'gitRecycleBasePath', 'getRecycleExpireTime', 'getLockWaitTime'"
12 | end
13 | rescue
14 | # ignore problems if plugin settings don't exist yet
15 | end
16 | end
17 |
18 | def self.down
19 | begin
20 | # Remove above settings from plugin page
21 | valuehash = (Setting.plugin_redmine_git_hosting).clone
22 | valuehash.delete('gitRecycleBasePath')
23 | valuehash.delete('gitRecycleExpireTime')
24 | valuehash.delete('gitLockWaitTime')
25 | if (Setting.plugin_redmine_git_hosting != valuehash)
26 | Setting.plugin_redmine_git_hosting = valuehash
27 | say "Removed redmine_git_hosting settings: 'gitRecycleBasePath', 'getRecycleExpireTime', 'getLockWaitTime'"
28 | end
29 | Setting.plugin_redmine_git_hosting = valuehash
30 | rescue
31 | # ignore problems if table doesn't exist yet....
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | .icon-push
2 | {
3 | background-image: url("../images/icon-divide.png");
4 | }
5 |
6 | pre.mirror-push {
7 | margin: 0 1em 1em 0em;
8 | padding: 2px;
9 | background-color: #fafafa;
10 | border: 1px solid #dadada;
11 | width:auto;
12 | overflow-x: auto;
13 | overflow-y: hidden;
14 | }
15 |
16 | pre.mirror-push.error {
17 | border: 1px solid #D71E1E;
18 | }
19 |
20 | .git_hosting_access_box {
21 | border: 2px solid;
22 | background-color: #dfffdf;
23 | border-color: #9fcf9f;
24 | color: #005f00;
25 | margin: -6px;
26 | padding: 4px;
27 | }
28 | .git_hosting_access_box p {
29 | padding-left:100px;
30 | margin-top: 8px;
31 | margin-bottom: 8px;
32 | }
33 | .git_hosting_access_box label { margin-left: -100px; width:95px; }
34 | .git_hosting_access_box em {
35 | font-style: italic;
36 | font-weight: bold;
37 | font-size: 110%;
38 | color: #467AA7;
39 | }
40 |
41 | .public_key_view {
42 | background-color: #fff;
43 | padding:5px;
44 | }
45 |
46 | .public_key_view label {
47 | font-weight: bold;
48 | text-align: right;
49 | }
50 |
51 | .public_key_view .myhead {
52 | font-style: italic;
53 | color: #000;
54 | size: 140%;
55 | padding: 10px 10px 0px 0px;
56 | margin-bottom: 5px;
57 | border-bottom: 1px solid #bbbbbb;
58 | }
59 |
60 | .public_key_view p {
61 | margin-top: 0px;
62 | margin-bottom: 5px;
63 | padding-top: 0px;
64 | }
65 |
66 | .public_key_view legend {
67 | font-style: italic;
68 | color: #000;
69 | size: 130%;
70 | }
71 |
--------------------------------------------------------------------------------
/app/views/repository_mirrors/_form.html.erb:
--------------------------------------------------------------------------------
1 |
<%= error_messages_for 'mirror' %>
2 |
3 |
4 |
5 |
<%= f.text_field :url, :required => true, :size => 65 %>
6 |
<%= f.select :push_mode, options_for_select([[l(:label_full_mirror),0],[l(:label_forced_update),1],[l(:label_fast_forward),2]], @mirror.push_mode), :label => :label_push_mode %>
7 |
8 |
<%= f.check_box :include_all_branches, :label => :field_include_all_branches %>
9 |
<%= f.check_box :include_all_tags, :label => :field_include_all_tags %>
10 |
<%= f.text_field :explicit_refspec, :size => 65 %>
11 |
12 |
<%= f.check_box :active %>
13 |
14 |
15 |
16 |
37 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/my_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'my_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module MyControllerPatch
9 | # Add in values for viewing public keys:
10 | def account_with_public_keys
11 | # Previous routine
12 | account_without_public_keys
13 |
14 | @gitolite_user_keys = @user.gitolite_public_keys.active.user_key.find(:all,:order => 'title ASC, created_at ASC')
15 | @gitolite_deploy_keys = @user.gitolite_public_keys.active.deploy_key.find(:all,:order => 'title ASC, created_at ASC')
16 | @gitolite_public_keys = @gitolite_user_keys + @gitolite_deploy_keys
17 | @gitolite_public_key = @gitolite_public_keys.detect{|x| x.id == params[:public_key_id].to_i}
18 | if @gitolite_public_key.nil?
19 | if params[:public_key_id]
20 | # public_key specified that doesn't belong to @user. Kill off public_key_id and try again
21 | redirect_to :public_key_id => nil, :tab => nil
22 | return
23 | else
24 | @gitolite_public_key = GitolitePublicKey.new
25 | end
26 | end
27 | end
28 |
29 | def self.included(base)
30 | base.class_eval do
31 | unloadable
32 |
33 | helper :gitolite_public_keys
34 | end
35 | begin
36 | base.send(:alias_method_chain, :account, :public_keys)
37 | rescue
38 | end
39 | end
40 | end
41 | end
42 | end
43 |
44 | # Patch in changes
45 | MyController.send(:include, GitHosting::Patches::MyControllerPatch)
46 |
--------------------------------------------------------------------------------
/tasks/gitolite.rake:
--------------------------------------------------------------------------------
1 | #
2 | # WARNING: Tasks in this file have been deprecated. See redmine_git_hosting.rake.
3 | #
4 | # There are two tasks here of interest: gitolite:update_repositories and gitolite:fetch_changesets.
5 | # The second includes the first (since fetching of changesets causes updating of gitolite config).
6 | #
7 | # As of the most recent release, either of these will complete resynchronize the gitolite configuration
8 | # and can thus be used to recover from errors that might have been introduced by sychronization errors.
9 | #
10 | # Specifically:
11 | #
12 | # 1) Resynchronize gitolite configuration (fix keys directory and configuration). Also, expire
13 | # repositories in the recycle_bin if time.
14 | #
15 | # rake gitolite:update_repositories RAILS_ENV=xxx
16 | #
17 | # 2) Fetch all changesets for repositories and then rescynronize gitolite configuration (as in #1)
18 | #
19 | # rake gitolite:fetch_changes RAILS_ENV=xxx
20 | #
21 | namespace :gitolite do
22 | desc "Update/repair gitolite configuration"
23 | task :update_repositories => [:environment] do
24 | puts "WARNING: This task deprecated. Use 'rake redmine_git_hosting:update_repositories' instead."
25 | Rake::Task["redmine_git_hosting:update_repositories"].invoke
26 | end
27 | desc "Fetch commits from gitolite repositories/update gitolite configuration"
28 | task :fetch_changes => [:environment] do
29 | puts "WARNING: This task deprecated. Use 'rake redmine_git_hosting:fetch_changesets' instead."
30 | Rake::Task["redmine_git_hosting:fetch_changesets"].invoke
31 | end
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/git_repository_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'repository'
5 | require_dependency 'repository/git'
6 |
7 | module GitHosting
8 | module Patches
9 | module GitRepositoryPatch
10 |
11 | # Set up git urls for new repositories
12 | def set_git_urls
13 | self.url = GitHosting.repository_path(self) if url.blank?
14 | self.root_url = url if root_url.blank?
15 | end
16 |
17 | def report_last_commit_with_always_true
18 | true
19 | end
20 | def extra_report_last_commit_with_always_true
21 | true
22 | end
23 |
24 | def fetch_changesets_with_disable_update
25 | # Turn of updates during repository update
26 | GitHostingObserver.set_update_active(false);
27 |
28 | # Do actual update
29 | fetch_changesets_without_disable_update
30 |
31 | # Reenable updates to perform a single update
32 | GitHostingObserver.set_update_active(true);
33 | end
34 |
35 | def self.included(base)
36 | base.class_eval do
37 | unloadable
38 |
39 | before_validation :set_git_urls
40 | end
41 |
42 | begin
43 | base.send(:alias_method_chain, :report_last_commit, :always_true)
44 | base.send(:alias_method_chain, :extra_report_last_commit, :always_true)
45 | base.send(:alias_method_chain, :fetch_changesets, :disable_update)
46 | rescue
47 | end
48 |
49 | end
50 | end
51 | end
52 | end
53 |
54 | # Patch in changes
55 | Repository::Git.send(:include, GitHosting::Patches::GitRepositoryPatch)
56 |
--------------------------------------------------------------------------------
/app/models/git_repository_extra.rb:
--------------------------------------------------------------------------------
1 | require 'digest/sha1'
2 |
3 | class GitRepositoryExtra < ActiveRecord::Base
4 |
5 | belongs_to :repository, :class_name => 'Repository', :foreign_key => 'repository_id'
6 | validates_associated :repository
7 | attr_accessible :id, :repository_id, :key, :git_http, :git_daemon, :notify_cia
8 |
9 | def after_initialize
10 | if self.repository.nil?
11 | generate
12 | setup_defaults
13 | end
14 | end
15 |
16 | def validate_encoded_time(clear_time, encoded_time)
17 | valid = false
18 | begin
19 | cur_time_seconds = Time.new.utc.to_i
20 | test_time_seconds = clear_time.to_i
21 | if cur_time_seconds - test_time_seconds < 5*60
22 | key = read_attribute(:key)
23 | test_encoded = Digest::SHA1.hexdigest(clear_time.to_s + key.to_s)
24 | if test_encoded.to_s == encoded_time.to_s
25 | valid = true
26 | end
27 | end
28 | rescue Exception=>e
29 | end
30 | valid
31 | end
32 |
33 | def generate
34 | if self.key.nil?
35 | write_attribute(:key, (0...64+rand(64) ).map{65.+(rand(25)).chr}.join )
36 | end
37 | end
38 |
39 | def setup_defaults
40 | write_attribute(:git_http,Setting.plugin_redmine_git_hosting['gitHttpDefault']) if Setting.plugin_redmine_git_hosting['gitHttpDefault']
41 | write_attribute(:git_daemon,Setting.plugin_redmine_git_hosting['gitDaemonDefault']) if Setting.plugin_redmine_git_hosting['gitDaemonDefault']
42 | write_attribute(:notify_cia,Setting.plugin_redmine_git_hosting['gitNotifyCIADefault']) if Setting.plugin_redmine_git_hosting['gitNotifyCIADefault']
43 | end
44 |
45 | end
46 |
--------------------------------------------------------------------------------
/db/migrate/2011081700000_move_notified_cia_to_git_cia_notifications.rb:
--------------------------------------------------------------------------------
1 | class MoveNotifiedCiaToGitCiaNotifications < ActiveRecord::Migration
2 | def self.up
3 |
4 | drop_table :git_cia_notifications if self.table_exists?("git_cia_notifications")
5 |
6 | create_table :git_cia_notifications do |t|
7 | t.column :repository_id, :integer
8 | t.column :scmid, :string
9 | end
10 |
11 | # Speed up searches
12 | add_index(:git_cia_notifications, :scmid)
13 | # Make sure uniqueness of the two columns, :scmid, :repository_id
14 | add_index(:git_cia_notifications, [:scmid, :repository_id], :unique => true)
15 |
16 | Project.find(:all).each {|project|
17 | if project.repository.is_a?(Repository::Git)
18 | project.repository.changesets.each { |changeset|
19 | if changeset.respond_to?(:notified_cia) and changeset.notified_cia == 1
20 | #project.repository.set_notified(changeset)
21 | project.repository.cia_notifications.push GitCiaNotification.new(:scmid => changeset.scmid)
22 | #cia_notification = GitCiaNotification.new
23 | #cia_notification.scmid = changeset.scmid
24 | #cia_notification.repository = project.repository
25 | #cia_notification.save
26 | end
27 | }
28 | end
29 | }
30 | remove_column :changesets, :notified_cia if self.column_exists?(:changesets, :notified_cia)
31 | end
32 |
33 | def self.down
34 | drop_table :git_cia_notifications
35 | end
36 |
37 | def self.table_exists?(name)
38 | ActiveRecord::Base.connection.tables.include?(name)
39 | end
40 |
41 | def self.column_exists?(table_name, column_name)
42 | columns(table_name).any?{ |c| c.name == column_name.to_s }
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/assets/javascripts/git_url_display.js:
--------------------------------------------------------------------------------
1 | var allGitUrlIds = ["git_url_ssh", "git_url_http", "git_url_git"]
2 | function updateGitUrl(el)
3 | {
4 | guHttpBase = guHttpBase.replace(/\/$/, "")
5 |
6 | var urls=[]
7 | var gitSHP = /:\d+$/.test(guGitServer)
8 | urls["git_url_ssh"] = [(gitSHP ? "ssh://" : "") + guGitUser + "@" + guGitServer + (gitSHP ? "/" : ":") + guSshURL, guUserIsCommitter]
9 | urls["git_url_http"] = [guHttpProto + "://" + ( (!guProjectIsPublic) || guUserIsCommitter ? encodeURIComponent(guUser) + "@" : "") + guHttpBase + "/" + guHttpURL, guUserIsCommitter]
10 | urls["git_url_git"] = ["git://" + guGitServer + "/" + guSshURL, false]
11 | var allGitUrlIds = ["git_url_ssh", "git_url_http", "git_url_git"]
12 |
13 | var selected_id = el.id
14 | document.getElementById("git_url_text").value = urls[selected_id][0];
15 | document.getElementById("git_url_access").innerHTML = urls[selected_id][1] ? "Read+Write" : "Read-Only"
16 |
17 | var i
18 | for(i=0;i
e
20 | # ignore problems if plugin settings don't exist yet
21 | end
22 | end
23 |
24 | def self.down
25 | begin
26 | # Remove above settings from plugin page
27 | valuehash = (Setting.plugin_redmine_git_hosting).clone
28 | valuehash.delete('gitDaemonDefault')
29 | valuehash.delete('gitHttpDefault')
30 | valuehash.delete('gitNotifyDIADefault')
31 | valuehash.delete('gitTempDataDir')
32 | valuehash.delete('gitScriptDir')
33 |
34 | if (Setting.plugin_redmine_git_hosting != valuehash)
35 | say "Removed redmine_git_hosting settings: 'gitDaemonDefault', 'gitHttpDefault', 'gitNotifyCIADefault', 'gitTempDataDir', 'gitScriptDir'"
36 | Setting.plugin_redmine_git_hosting = valuehash
37 | end
38 | rescue => e
39 | # ignore problems if table doesn't exist yet....
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/app/views/my/account.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %>
3 | <%= call_hook(:view_my_account_contextual, :user => @user)%>
4 |
5 | <%=l(:label_my_account)%>
6 | <%= error_messages_for 'user' %>
7 |
8 |
9 | <% labelled_form_for :user, @user,
10 | :url => { :action => "account" },
11 | :html => { :id => 'my_account_form',
12 | :method => :post } do |f| %>
13 |
14 | <%=l(:label_information_plural)%>
15 | <%= f.text_field :firstname, :required => true %>
16 | <%= f.text_field :lastname, :required => true %>
17 | <%= f.text_field :mail, :required => true %>
18 | <%= f.select :language, lang_options_for_select %>
19 | <% if Setting.openid? %>
20 | <%= f.text_field :identity_url %>
21 | <% end %>
22 | <% @user.custom_field_values.select(&:editable?).each do |value| %>
23 | <%= custom_field_tag_with_label :user, value %>
24 | <% end %>
25 | <%= call_hook(:view_my_account, :user => @user, :form => f) %>
26 |
27 |
28 | <%=l(:field_mail_notification)%>
29 | <%= render :partial => 'users/mail_notifications' %>
30 |
31 |
32 | <%=l(:label_preferences)%>
33 | <%= render :partial => 'users/preferences' %>
34 |
35 | <%= submit_tag l(:button_save) %>
36 |
37 | <% end %>
38 |
39 |
40 |
41 | <%= render :partial => 'gitolite_public_keys/view' %>
42 |
43 |
44 | <% content_for :sidebar do %>
45 | <%= render :partial => 'my/sidebar' %>
46 | <% end %>
47 | <% html_title(l(:label_my_account)) -%>
48 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/project_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'project'
5 |
6 | module GitHosting
7 | module Patches
8 | module ProjectPatch
9 | # Find all repositories owned by project which are Repository::Git
10 | # Works for both multi- and single- repo/project
11 | def gl_repos
12 | all_repos.select{|x| x.is_a?(Repository::Git)}
13 | end
14 |
15 | # Find all repositories owned by project. Works for both multi- and
16 | # single- repo/project
17 | def all_repos
18 | if GitHosting.multi_repos?
19 | repositories
20 | else
21 | [ repository ].compact
22 | end
23 | end
24 |
25 | # Return first repo with a blank identifier (should be only one!)
26 | def repo_blank_ident
27 | Repository.find_by_project_id(id,:conditions => ["identifier = '' or identifier is null"])
28 | end
29 |
30 | # Make sure that identifier does not match existing repository identifier
31 | # Only for Redmine 1.4
32 | def additional_ident_constraints
33 | if new_record? && !identifier.blank? && Repository.find_by_identifier_and_type(identifier,"Git")
34 | errors.add(:identifier,:ident_not_unique)
35 | end
36 | end
37 |
38 | def self.included(base)
39 | base.class_eval do
40 | unloadable
41 |
42 | named_scope :archived, { :conditions => {:status => "#{Project::STATUS_ARCHIVED}"}}
43 | named_scope :active_or_archived, { :conditions => "status=#{Project::STATUS_ACTIVE} OR status=#{Project::STATUS_ARCHIVED}" }
44 |
45 | # Place additional constraints on repository identifiers
46 | # Only for Redmine 1.4+
47 | if GitHosting.multi_repos?
48 | validate :additional_ident_constraints
49 | end
50 | end
51 | end
52 | end
53 | end
54 | end
55 |
56 | # Patch in changes
57 | Project.send(:include, GitHosting::Patches::ProjectPatch)
58 |
--------------------------------------------------------------------------------
/db/migrate/20120803043256_create_deployment_credentials.rb:
--------------------------------------------------------------------------------
1 | class CreateDeploymentCredentials < ActiveRecord::Migration
2 | def self.up
3 | begin
4 | create_table :deployment_credentials do |t|
5 | t.references :repository
6 | t.references :gitolite_public_key
7 | t.references :user
8 | t.column :active, :integer, :default => 1
9 | t.column :perm, :string, :null => false
10 | end
11 | add_index :deployment_credentials, :repository_id
12 | add_index :deployment_credentials, :gitolite_public_key_id
13 |
14 | add_column :gitolite_public_keys, :key_type, :integer, :default => GitolitePublicKey::KEY_TYPE_USER
15 | add_column :gitolite_public_keys, :delete_when_unused, :boolean, :default => true
16 |
17 | GitHostingObserver.set_update_active(false)
18 |
19 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
20 | manager_role.add_permission! :view_deployment_keys
21 | manager_role.add_permission! :edit_deployment_keys
22 | manager_role.add_permission! :create_deployment_keys
23 | manager_role.save
24 |
25 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
26 | developer_role.add_permission! :view_deployment_keys
27 | developer_role.save
28 | rescue => e
29 | puts "#{e}"
30 | end
31 | end
32 |
33 | def self.down
34 | begin
35 | drop_table :deployment_credentials
36 | remove_column :gitolite_public_keys, :key_type
37 | remove_column :gitolite_public_keys, :delete_when_unused
38 |
39 | GitHostingObserver.set_update_active(false)
40 | manager_role = Role.find_by_name(I18n.t(:default_role_manager))
41 | manager_role.remove_permission! :view_deployment_keys
42 | manager_role.remove_permission! :edit_deployment_keys
43 | manager_role.remove_permission! :create_deployment_keys
44 | manager_role.save
45 |
46 | developer_role = Role.find_by_name(I18n.t(:default_role_developer))
47 | developer_role.remove_permission! :view_deployment_keys
48 | developer_role.save
49 | rescue => e
50 | puts "#{e}"
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/db/migrate/20111220055819_add_settings_to_plugin_2.rb:
--------------------------------------------------------------------------------
1 | class AddSettingsToPlugin2 < ActiveRecord::Migration
2 | def self.up
3 | begin
4 | # Add some new settings to settings page, if they don't exist
5 | valuehash = (Setting.plugin_redmine_git_hosting).clone
6 | valuehash['httpServerSubdir'] ||= ''
7 | valuehash['gitRedmineSubdir'] ||= ''
8 | valuehash['gitRepositoryHierarchy'] ||= 'true'
9 |
10 | # Fix httpServer by removing directory components
11 | valuehash['httpServer'] = (valuehash['httpServer'][/^[^\/]*/])
12 |
13 | if (Setting.plugin_redmine_git_hosting != valuehash)
14 | say "Added redmine_git_hosting settings: 'httpServerSubdir', 'gitRedmineSubdir', 'gitRepositoryHierarchy'"
15 | if (Setting.plugin_redmine_git_hosting['httpServer'] != valuehash['httpServer'])
16 | say "Updated 'httpServer' from '#{Setting.plugin_redmine_git_hosting['httpServer']}' to '#{valuehash['httpServer']}'."
17 | end
18 | Setting.plugin_redmine_git_hosting = valuehash
19 | end
20 | rescue => e
21 | # ignore problems if plugin settings don't exist yet
22 | end
23 | end
24 |
25 | def self.down
26 | begin
27 | # Remove above settings from plugin page
28 | valuehash = (Setting.plugin_redmine_git_hosting).clone
29 | valuehash.delete('httpServerSubdir')
30 | valuehash.delete('gitRedmineSubdir')
31 | valuehash.delete('gitRepositoryHierarchy')
32 |
33 | # Restore redmine root directory to httpServer (remove trailing '/')
34 | valuehash['httpServer'] = GitHosting.my_root_url
35 |
36 | if (Setting.plugin_redmine_git_hosting != valuehash)
37 | say "Removed redmine_git_hosting settings: 'httpServerSubdir', 'gitRedmineSubdir', 'gitRepositoryHierarchy'"
38 | if (Setting.plugin_redmine_git_hosting['httpServer'] != valuehash['httpServer'])
39 | say "Updated 'httpServer' from '#{Setting.plugin_redmine_git_hosting['httpServer']}' to '#{valuehash['httpServer']}'."
40 | end
41 | Setting.plugin_redmine_git_hosting = valuehash
42 | end
43 | rescue => e
44 | # ignore problems if table doesn't exist yet....
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/assets/stylesheets/modalbox/modalbox.css:
--------------------------------------------------------------------------------
1 | #MB_overlay {
2 | position: absolute;
3 | margin: auto;
4 | top: 0; left: 0;
5 | width: 100%; height: 100%;
6 | z-index: 9999;
7 | background-color: #000!important;
8 | }
9 | #MB_overlay[id] { position: fixed; }
10 |
11 | #MB_window {
12 | position: absolute;
13 | top: 0;
14 | border: 0 solid;
15 | text-align: left;
16 | z-index: 10000;
17 | }
18 | #MB_window[id] { position: fixed!important; }
19 |
20 | #MB_frame {
21 | position: relative;
22 | background-color: #EFEFEF;
23 | height: 100%;
24 | }
25 |
26 | #MB_header {
27 | margin: 0;
28 | padding: 0;
29 | }
30 |
31 | #MB_content {
32 | padding: 6px .75em;
33 | overflow: auto;
34 | }
35 |
36 | #MB_caption {
37 | font: bold 100% "Lucida Grande", Arial, sans-serif;
38 | text-shadow: #FFF 0 1px 0;
39 | padding: .5em 2em .5em .75em;
40 | margin: 0;
41 | text-align: left;
42 | }
43 |
44 | #MB_close {
45 | display: block;
46 | position: absolute;
47 | right: 5px; top: 4px;
48 | padding: 2px 3px;
49 | font-weight: bold;
50 | text-decoration: none;
51 | font-size: 13px;
52 | }
53 | #MB_close:hover {
54 | background: transparent;
55 | }
56 |
57 | #MB_loading {
58 | padding: 1.5em;
59 | text-indent: -10000px;
60 | background: transparent url(spinner.gif) 50% 0 no-repeat;
61 | }
62 |
63 | /* Color scheme */
64 | #MB_frame {
65 | padding-bottom: 7px;
66 | -webkit-border-radius: 7px;
67 | -moz-border-radius: 7px;
68 | border-radius: 7px;
69 | }
70 | #MB_window {
71 | background-color: #EFEFEF;
72 | color: #000;
73 | -webkit-box-shadow: 0 8px 64px #000;
74 | -moz-box-shadow: 0 0 64px #000;
75 | box-shadow: 0 0 64px #000;
76 |
77 | -webkit-border-radius: 7px;
78 | -moz-border-radius: 7px;
79 | border-radius: 7px;
80 | }
81 | #MB_content { border-top: 1px solid #F9F9F9; }
82 | #MB_header {
83 | background-color: #DDD;
84 | border-bottom: 1px solid #CCC;
85 | }
86 | #MB_caption { color: #000 }
87 | #MB_close { color: #777 }
88 | #MB_close:hover { color: #000 }
89 |
90 |
91 | /* Alert message */
92 | .MB_alert {
93 | margin: 10px 0;
94 | text-align: center;
95 | }
--------------------------------------------------------------------------------
/app/views/repositories/git_instructions.html.erb:
--------------------------------------------------------------------------------
1 | <%# This is used to display basic git setup instructions, like on github... %>
2 | <% flash.now[:warning] = "Repository is empty. Get started by following the instructions below." %>
3 |
4 | <%= render :partial => 'git_urls', :locals => {:repository => @repository, :project => @project} %>
5 |
6 | <% gitSHP = Setting.plugin_redmine_git_hosting['gitServer'].match(/:\d+$/) %>
7 | <% git_ssh_url =
8 | "#{gitSHP ? 'ssh://' : ''}#{Setting.plugin_redmine_git_hosting['gitUser']}@#{Setting.plugin_redmine_git_hosting['gitServer']}#{gitSHP ? '/' : ':'}#{GitHosting.repository_name(@repository)}.git" %>
9 |
10 |
11 |
12 |
Git Setup:
13 |
Download and Install Git
14 | git config --global user.name "<%= User.current.name(:firstname_lastname) %>"
15 | git config --global user.email <%= User.current.mail %>
16 | <% if User.current.gitolite_public_keys.active.length == 0 %><%= "\t" + (link_to "Upload SSH Public Key", {:controller => 'my', :action => 'account'}) + "\n " %><% else %><%= "" %><% end %>
17 |
Repository Setup:
18 |
mkdir <%= @repository.git_name %>
19 | cd <%= @repository.git_name %>
20 | git init
21 | touch readme.txt
22 | git add readme.txt
23 | git commit -m 'Initializing <%= @repository.git_label %> repository'
24 | git remote add origin <%= git_ssh_url %>
25 | git push -u origin master
26 |
27 |
Existing Git Repo?
28 |
cd existing_git_repo
29 | git remote add origin <%= git_ssh_url %>
30 | git push -u origin master
31 |
32 |
33 |
34 | <% if @repositories.size > 1 %>
35 | <% content_for :sidebar do %>
36 | <%= l(:label_repository_plural) %>
37 |
38 | <%= @repositories.sort.collect {|repo|
39 | link_to h(repo.name),
40 | {:controller => 'repositories', :action => 'show',
41 | :id => @project, :repository_id => repo.identifier_param, :rev => nil, :path => nil},
42 | :class => 'repository' + (repo == @repository ? ' selected' : '')
43 | }.join(' ').html_safe %>
44 |
45 | <% end %>
46 | <% end %>
47 |
--------------------------------------------------------------------------------
/app/views/deployment_credentials/_form_with_key.html.erb:
--------------------------------------------------------------------------------
1 | <%= error_messages_for 'cred' %>
2 |
3 |
4 |
5 | <% labelled_fields_for :gitolite_public_key, @key do |k| %>
6 |
7 | <% if !@user_keys.empty? || !@other_keys.empty? %>
8 | <% option_array = [[l(:select_create_new_key),-1]] %>
9 | <% option_array += (@user_keys.map {|key| [keylabel_text(key),key.id]}) %>
10 | <% if !@other_keys.empty? %>
11 | <% option_array2 = (@other_keys.map {|key| [keylabel_text(key), key.id]}) %>
12 | <% maxlen = (option_array+option_array2).map{|x|x.first.length}.max %>
13 | <% extra = ([maxlen - l(:select_other_keys).length - 2,6].max)/2 %>
14 | <% option_array += [[("-"*extra)+" "+l(:select_other_keys)+" "+"-"*extra, -2]] %>
15 | <% option_array += option_array2 %>
16 | <% end %>
17 |
<%= k.select :id, options_for_select(option_array, :selected => -1, :disabled => [-2]+@disabled_keys.map(&:id)), :required => true, :label => :label_which_deploy_key %>
18 | <% end %>
19 |
<%= f.select :perm, options_for_select(DeploymentCredential::valid_perms,DeploymentCredential::default_perm), :required => true, :label => :label_deploy_perm %>
20 |
21 |
22 |
<%= l(:label_public_key_new) %>
23 | <%= k.text_field :title, :label => :label_identifier_can_be_arbitrary, :required => true, :style => 'width:99%;' %>
24 | <%= k.check_box :delete_when_unused, :required => true, :label => :field_delete_when_unused %>
25 | <%= k.text_area :key, :required => true, :label => :label_cut_and_paste,
26 | :style => "width:99%;height:125px;overflow:auto;",
27 | :cols => nil, :rows => nil %>
28 |
29 |
30 | <% end %>
31 |
32 |
33 |
34 |
55 |
--------------------------------------------------------------------------------
/assets/stylesheets/zero_clipboard.css:
--------------------------------------------------------------------------------
1 | #clipboard_button
2 | {
3 | background-color: #eee;
4 | background: url('../images/button.svg') 0 0 no-repeat; /* Opera needs an "image" :( - using svg for this so it will scale properly without looking too ugly */
5 | background: -khtml-gradient(linear, left top, left bottom, from(#f8f8f8), to(#ddd)); /* Konquerer */
6 | background: -moz-linear-gradient(top, #f8f8f8, #ddd); /* Gecko (Firefox, ...) */
7 | background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#ddd)); /* Webkit (Chrome, Safari, ...) */
8 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#dddddd'); /* IE 5.5 - 7 */
9 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#dddddd'); /* IE 8 */
10 |
11 | border-color: #bbb;
12 | border-style: solid;
13 | border-width: 1px 1px 1px 0;
14 |
15 | color: #333;
16 | display: block;
17 | font-size: 11px;
18 | font-weight: bold;
19 | line-height: 21px;
20 | margin: 0;
21 | padding: 0 10px 0 11px;
22 | text-decoration: none;
23 | text-shadow: 1px 1px 0 #fff;
24 | position: relative; /* to please IE */
25 | }
26 |
27 | #clipboard_button.active
28 | {
29 | background-color: #bbb;
30 | background: url('../images/button_selected.svg') 0 0 no-repeat; /* Opera needs an "image" :( - using svg for this so it will scale properly without looking too ugly */
31 | background: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#aaa)); /* Konquerer */
32 | background: -moz-linear-gradient(top, #ccc, #aaa); /* Gecko (Firefox, ...) */
33 | background: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#aaa)); /* Webkit (Chrome, Safari, ...) */
34 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#aaaaaa'); /* IE 5.5 - IE 7 */
35 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#aaaaaa'); /* IE 8 */
36 |
37 | color: #000;
38 | text-shadow: 1px 1px 0 rgba(255,255,255,0.4);
39 | border-color: #bbb;
40 | }
41 |
42 |
43 |
44 |
45 | #clipboard_container
46 | {
47 | position: relative;
48 | float: left;
49 | margin-left: 5px;
50 | }
51 |
52 | #clipboard_button
53 | {
54 | height: 21px;
55 | width: 23px;
56 | padding: 0;
57 | border-width: 1px;
58 | text-align: center;
59 |
60 | border-radius: 5px; /* Standard, Opera 10, IE 9 */
61 | -khtml-border-radius: 3px; /* Konquerer */
62 | -moz-border-radius: 3px ; /* Gecko (Firefox, ...) */
63 | -webkit-border-radius: 3px; /* Webkit (Chrome, Safari, ...) */
64 | /* IE <= 9 not supported */
65 | }
66 |
67 | #clipboard_button img
68 | {
69 | padding-top: 2px;
70 | }
71 |
--------------------------------------------------------------------------------
/app/models/deployment_credential.rb:
--------------------------------------------------------------------------------
1 | class DeploymentCredential < ActiveRecord::Base
2 | STATUS_ACTIVE = 1
3 | STATUS_INACTIVE = 0
4 |
5 | belongs_to :repository
6 | belongs_to :gitolite_public_key
7 | belongs_to :user
8 |
9 | attr_accessible :perm
10 | validates_presence_of :perm, :user, :repository
11 | validates_presence_of :gitolite_public_key
12 | validate :correct_key_type, :correct_perm_type, :no_duplicate_creds
13 | validate :owner_matches_key
14 |
15 | named_scope :active, {:conditions => {:active => STATUS_ACTIVE}}
16 | named_scope :inactive, {:conditions => {:active => STATUS_INACTIVE}}
17 |
18 | def perm= (value)
19 | write_attribute(:perm, (value.upcase rescue nil))
20 | end
21 |
22 | # Provide a role-like interface.
23 | # Support :commit_access and :view_changesets
24 | @@equivalence = nil
25 | def allowed_to?( cred )
26 | @@equivalence ||= {
27 | :view_changesets => ["R","RW+"],
28 | :commit_access => ["RW+"]
29 | }
30 | return false unless honored?
31 |
32 | # Deployment Credentials equivalence matrix
33 | return false unless @@equivalence[cred] && @@equivalence[cred].index(perm)
34 | true
35 | end
36 |
37 | # Deployment Credentials ignored unless created by someone who still has permission to create them
38 | def honored?
39 | user.admin? || user.allowed_to?(:create_deployment_keys,repository.project)
40 | end
41 |
42 | def self.valid_perms
43 | ["R", "RW+"]
44 | end
45 |
46 | def self.default_perm
47 | "RW+"
48 | end
49 |
50 | def to_s
51 | return File.join("Deploy Key: #{repository.identifier}-#{gitolite_public_key.identifier}: #{mode.to_s}")
52 | end
53 |
54 | protected
55 |
56 | def correct_key_type
57 | if gitolite_public_key && gitolite_public_key.key_type != GitolitePublicKey::KEY_TYPE_DEPLOY
58 | errors.add_to_base("Public Key Must Be a Deployment Key")
59 | end
60 | end
61 |
62 | def correct_perm_type
63 | if !self.class.valid_perms.index(perm)
64 | errors.add(:perm, "must be one of #{self.class.valid_perms.join(',')}")
65 | end
66 | end
67 |
68 | def owner_matches_key
69 | return if user.nil? || gitolite_public_key.nil?
70 | if user != gitolite_public_key.user
71 | errors.add_to_base("Credential owner cannot be different than owner of Key.")
72 | end
73 | end
74 |
75 | def no_duplicate_creds
76 | return if !new_record? || repository.nil? || gitolite_public_key.nil?
77 | repository.deployment_credentials.each do |cred|
78 | if cred.gitolite_public_key == gitolite_public_key
79 | errors.add_to_base("This Public Key has already been used in a Deployment Credential for this repository.")
80 | end
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/db/migrate/2011081300000_create_git_repository_extras.rb:
--------------------------------------------------------------------------------
1 | class CreateGitRepositoryExtras < ActiveRecord::Migration
2 | def self.up
3 |
4 | drop_table :git_repository_extras if self.table_exists?("git_repository_extras")
5 |
6 | create_table :git_repository_extras do |t|
7 | t.column :repository_id, :integer
8 | # from repository extra columns
9 | t.column :git_daemon, :integer, :default =>1
10 | t.column :git_http, :integer, :default=>1
11 | t.column :notify_cia, :integer, :default=>0
12 | # from Hooks Keys table
13 | t.column :key, :string
14 | end
15 |
16 |
17 | GitHostingObserver.set_update_active(false)
18 | Project.find(:all).each do |project|
19 | if project.repository.is_a?(Repository::Git)
20 |
21 | #create extra object
22 | e = GitRepositoryExtra.new()
23 | begin
24 | e.git_daemon = project.repository.git_daemon || 1
25 | e.git_http = project.repository.git_http || 1
26 | e.key = project.repository.hook_key.key
27 | rescue
28 | e.git_daemon = 1
29 | e.git_http = 1
30 | end
31 | e.repository_id = project.repository.id
32 | e.save
33 |
34 | #update repo url to match location of gitolite repos
35 | r = project.repository
36 | repo_name= project.parent ? File.join(GitHosting::get_full_parent_path(project, true),project.identifier) : project.identifier
37 | r.url = File.join(Setting.plugin_redmine_git_hosting['gitRepositoryBasePath'], "#{repo_name}.git")
38 | r.root_url = r.url
39 | r.extra = e
40 | r.save
41 |
42 | end
43 | end
44 |
45 | # this next part requires running commands as git user
46 | # use a begin/rescue block because this could easily bomb out
47 | # if settings aren't correct to begin with
48 | begin
49 | %x[ rm -rf '#{ GitHosting.get_tmp_dir }' ]
50 | GitHosting.setup_hooks
51 | GitHostingObserver.set_update_active(false)
52 | rescue
53 | end
54 |
55 | # even if git commands above didn't work properly, attempt to
56 | # eliminate tmp dir in case they partially worked, and we have
57 | # residual crap belonging to wrong user
58 | begin
59 | %x[ rm -rf '#{ GitHosting.get_tmp_dir }' ]
60 | rescue
61 | end
62 |
63 |
64 | if self.table_exists?("git_hook_keys")
65 | drop_table :git_hook_keys
66 | end
67 | if self.column_exists?(:repositories, :git_daemon)
68 | remove_column :repositories, :git_daemon
69 | end
70 | if self.column_exists?(:repositories, :git_http)
71 | remove_column :repositories, :git_http
72 | end
73 |
74 | end
75 |
76 | def self.down
77 | drop_table :git_repository_extras
78 | end
79 |
80 | def self.table_exists?(name)
81 | ActiveRecord::Base.connection.tables.include?(name)
82 | end
83 | def self.column_exists?(table_name, column_name)
84 | columns(table_name).any?{ |c| c.name == column_name.to_s }
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/app/models/cia_notification_mailer.rb:
--------------------------------------------------------------------------------
1 | require "xmlrpc/client"
2 |
3 | class CiaNotificationMailer < ActionMailer::Base
4 |
5 | helper :git_hosting
6 | include GitHostingHelper
7 |
8 | def notification(revision, branch)
9 | @subject = "DeliverXML"
10 | @recipients = ["cia@cia.vc"]
11 | #@recipients = ["ufs@ufsoft.org"]
12 | @content_type = "text/xml"
13 | from "CIABOT-NOREPLY@#{ Setting['host_name'].match('localhost')? Setting['mail_from'].split('@')[-1] : Setting['host_name'] }"
14 | @sent_on = Time.now
15 | @body = render_message(
16 | "cia_notification.erb", :revision => revision, :branch => branch,
17 | :plugin => Redmine::Plugin.find('redmine_git_hosting')
18 | )
19 | GitHosting.logger.debug "---8<----8<--- CIA Notification Body ---8<----8<---\n#{body}---8<----8<--- CIA Notification Body ---8<----8<---"
20 | @headers = {
21 | "Message-ID" => "<#{revision.revision}.#{revision.author}@#{revision.project.name}>"
22 | }
23 | end
24 |
25 |
26 | # Overrides default deliver! method to first try to deliver the CIA notification
27 | # through RPC(3 seconds timeout). If failed, send it by email.
28 | def deliver!(mail = @mail)
29 |
30 | rpc_server = XMLRPC::Client.new(
31 | host="www.cia.vc", path="/RPC2", port=nil, proxy_host=nil,
32 | proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout=3
33 | )
34 |
35 | begin
36 | ok, result = rpc_server.call2("hub.deliver", @body)
37 | if ok:
38 | GitHosting.logger.info "RPC Called. OK => #{ok} Result => #{result}"
39 | return false
40 | end
41 | GitHosting.logger.info "Failed to post the RPC call: #{result}"
42 | rescue XMLRPC::FaultException => e
43 | GitHosting.logger.info "RPC Failed. Error => #{e}"
44 | rescue Errno::ECONNREFUSED => e
45 | GitHosting.logger.info "RPC Connection Refused. Error => #{e}"
46 | rescue SocketError => e
47 | GitHosting.logger.info "RPC Socket Error. Error => #{e}"
48 | rescue Exception => e
49 | GitHosting.logger.info "RPC Error. Error => #{e}"
50 | end
51 |
52 | GitHosting.logger.info "Delivering By Email"
53 |
54 | return false if (recipients.nil? || recipients.empty?) &&
55 | (cc.nil? || cc.empty?) &&
56 | (bcc.nil? || bcc.empty?)
57 |
58 | # Log errors when raise_delivery_errors is set to false, Rails does not
59 | raise_errors = self.class.raise_delivery_errors
60 | self.class.raise_delivery_errors = true
61 | begin
62 | return super(mail)
63 | rescue Exception => e
64 | if raise_errors
65 | raise e
66 | elsif mylogger
67 | GitHosting.logger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
68 | end
69 | ensure
70 | self.class.raise_delivery_errors = raise_errors
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/roles_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'roles_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module RolesControllerPatch
9 | # Pre-1.4 (Not RESTfull)
10 | def new_with_disable_update
11 | # Turn of updates during repository update
12 | GitHostingObserver.set_update_active(false);
13 |
14 | # Do actual update
15 | new_without_disable_update
16 |
17 | # Reenable updates to perform a single update
18 | GitHostingObserver.set_update_active(true);
19 | end
20 |
21 | # Post-1.4 (RESTfull)
22 | def create_with_disable_update
23 | # Turn of updates during repository update
24 | GitHostingObserver.set_update_active(false);
25 |
26 | # Do actual update
27 | create_without_disable_update
28 |
29 | # Reenable updates to perform a single update
30 | GitHostingObserver.set_update_active(true);
31 | end
32 |
33 | # Pre-1.4 (Not RESTfull)
34 | def edit_with_disable_update
35 | # Turn of updates during repository update
36 | GitHostingObserver.set_update_active(false);
37 |
38 | # Do actual update
39 | edit_without_disable_update
40 |
41 | # Reenable updates to perform a single update
42 | GitHostingObserver.set_update_active(true);
43 | end
44 |
45 | # Post-1.4 (RESTfull)
46 | def update_with_disable_update
47 | # Turn of updates during repository update
48 | GitHostingObserver.set_update_active(false);
49 |
50 | # Do actual update
51 | update_without_disable_update
52 |
53 | # Reenable updates to perform a single update
54 | GitHostingObserver.set_update_active(true);
55 | end
56 |
57 | def destroy_with_disable_update
58 | # Turn of updates during repository update
59 | GitHostingObserver.set_update_active(false);
60 |
61 | # Do actual update
62 | destroy_without_disable_update
63 |
64 | # Reenable updates to perform a single update
65 | GitHostingObserver.set_update_active(true);
66 | end
67 | def self.included(base)
68 | base.class_eval do
69 | unloadable
70 | end
71 | begin
72 | # RESTfull (post-1.4)
73 | base.send(:alias_method_chain, :create, :disable_update)
74 | rescue
75 | # Not RESTfull (pre-1.4)
76 | base.send(:alias_method_chain, :new, :disable_update) rescue nil
77 | end
78 | begin
79 | # RESTfull (post-1.4)
80 | base.send(:alias_method_chain, :update, :disable_update)
81 | rescue
82 | # Not RESTfull (pre-1.4)
83 | base.send(:alias_method_chain, :edit, :disable_update) rescue nil
84 | end
85 |
86 | base.send(:alias_method_chain, :destroy, :disable_update) rescue nil
87 | end
88 | end
89 | end
90 | end
91 |
92 | # Patch in changes
93 | RolesController.send(:include, GitHosting::Patches::RolesControllerPatch)
94 |
--------------------------------------------------------------------------------
/assets/javascripts/modalbox/lib/scriptaculous.js:
--------------------------------------------------------------------------------
1 | // script.aculo.us scriptaculous.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
2 |
3 | // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining
6 | // a copy of this software and associated documentation files (the
7 | // "Software"), to deal in the Software without restriction, including
8 | // without limitation the rights to use, copy, modify, merge, publish,
9 | // distribute, sublicense, and/or sell copies of the Software, and to
10 | // permit persons to whom the Software is furnished to do so, subject to
11 | // the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be
14 | // included in all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | //
24 | // For details, see the script.aculo.us web site: http://script.aculo.us/
25 |
26 | var Scriptaculous = {
27 | Version: '1.8.1',
28 | require: function(libraryName) {
29 | // inserting via DOM fails in Safari 2.0, so brute force approach
30 | document.write('
33 | <% end %>
34 |
35 | <% if (!User.current.anonymous?) || repository.extra[:git_http].to_s != "0" || (project.is_public && repository.extra[:git_daemon].to_s != "0" ) %>
36 |
37 |
38 |
Repository Access Links:
39 |
40 |
<%= image_tag 'paste.png', :plugin => 'redmine_git_hosting' %>
41 |
42 |
43 | <% if !User.current.anonymous? %>
44 | SSH
45 | <% end %>
46 | <% if repository.extra[:git_http].to_s != "0" %>
47 | HTTP
48 | <% end %>
49 | <% if project.is_public && repository.extra[:git_daemon].to_s != "0" %>
50 | Git
51 | <% end %>
52 |
53 |
54 |
This URL has Read-Only access.
55 |
56 |
57 | <% end %>
58 | <% end %>
59 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 |
3 | #
4 | # These functions are for backward compatability with versions of redmine < 1.3
5 | # Only define these if not already defined (although load-order seems to load plugin
6 | # helpers before main ones, so check not necessary).
7 | #
8 | # 1/05/12 John Kubiatowicz
9 | # 4/01/12 Only define backward-compatible functions if TabularFormBuilder exists
10 | # (seems some versions of rails will go ahead and define these functions
11 | # and override properly defined versions). Note that Redmine 1.4+ removes
12 | # lib/tabular_form_builder.rb but defines these functions using new
13 | # builder functions...
14 | # 8/10/12 Added "labelled_fields_for", since that seems to be coming in 1.4
15 | if !defined?(labelled_form_for) && File.exists?(Rails.root.join("lib/tabular_form_builder.rb"))
16 | def labelled_form_for(*args, &proc)
17 | args << {} unless args.last.is_a?(Hash)
18 | options = args.last
19 | options.merge!({:builder => TabularFormBuilder,:lang => current_language})
20 | form_for(*args, &proc)
21 | end
22 | end
23 |
24 | if !defined?(labelled_remote_form_for) && File.exists?(Rails.root.join("lib/tabular_form_builder.rb"))
25 | def labelled_remote_form_for(*args, &proc)
26 | args << {} unless args.last.is_a?(Hash)
27 | options = args.last
28 | options.merge!({:builder => TabularFormBuilder,:lang => current_language})
29 | remote_form_for(*args, &proc)
30 | end
31 | end
32 |
33 | if !defined?(labelled_fields_for) && File.exists?(Rails.root.join("lib/tabular_form_builder.rb"))
34 | def labelled_fields_for(*args, &proc)
35 | args << {} unless args.last.is_a?(Hash)
36 | options = args.last
37 | options.merge!({:builder => TabularFormBuilder,:lang => current_language})
38 | fields_for(*args, &proc)
39 | end
40 | end
41 |
42 | # Generic helper functions
43 | def reldir_add_dotslash(path)
44 | # Is this a relative path?
45 | stripped = (path || "").lstrip.rstrip
46 | norm = File.expand_path(stripped,"/")
47 | ((stripped[0,1] != "/")?".":"") + norm + ((norm[-1,1] != "/")?"/":"")
48 | end
49 |
50 | # Port-receive Mode
51 | def post_receive_mode(prurl)
52 | if prurl.active==0
53 | l(:label_inactive)
54 | elsif prurl.mode == :github
55 | l(:label_github_post)
56 | else
57 | l(:label_empty_get)
58 | end
59 | end
60 |
61 | # Refspec for mirrors
62 | def refspec(mirror, max_refspec=0)
63 | if mirror.push_mode==RepositoryMirror::PUSHMODE_MIRROR
64 | l(:all_references)
65 | else
66 | result=[]
67 | result << l(:all_branches) if mirror.include_all_branches
68 | result << l(:all_tags) if mirror.include_all_tags
69 | result << mirror.explicit_refspec if (max_refspec == 0) || ((1..max_refspec) === mirror.explicit_refspec.length)
70 | result << l(:explicit) if (max_refspec > 0) && (mirror.explicit_refspec.length > max_refspec)
71 | result.join(", ")
72 | end
73 | end
74 |
75 | # Mirror Mode
76 | def mirror_mode(mirror)
77 | if mirror.active==0
78 | l(:label_inactive)
79 | else
80 | [l(:label_mirror),l(:label_forced),l(:label_unforced)][mirror.push_mode]
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/app/views/projects/_git_urls.erb:
--------------------------------------------------------------------------------
1 | <% if project.repository && project.repository.is_a?(Repository::Git) %>
2 | <% content_for :header_tags do %>
3 |
4 | <%= stylesheet_link_tag('git_url_display', :plugin => 'redmine_git_hosting') %>
5 | <%= javascript_include_tag('git_url_display', :plugin => 'redmine_git_hosting') %>
6 |
7 | <%= stylesheet_link_tag('zero_clipboard', :plugin => 'redmine_git_hosting') %>
8 | <%= javascript_include_tag('ZeroClipboard', :plugin => 'redmine_git_hosting') %>
9 | <%= javascript_include_tag('zero_clipboard_setup', :plugin => 'redmine_git_hosting') %>
10 |
11 |
12 |
33 | <% end %>
34 |
35 | <% if (project.module_enabled?(:repository) && Setting.plugin_redmine_git_hosting['gitRepositoriesShowUrl'].to_s != "false" ) && ((!User.current.anonymous?) || project.repository.extra[:git_http].to_s != "0" || (project.is_public && project.repository.extra[:git_daemon].to_s != "0" )) %>
36 |
37 | <% if GitHosting.multi_repos? && project.repositories.count > 1 %>
38 |
Default Git Repository
39 | <% else %>
40 |
Git Repository
41 | <% end %>
42 |
43 |
44 |
<%= image_tag 'paste.png', :plugin => 'redmine_git_hosting' %>
45 |
46 |
47 | <% if !User.current.anonymous? %>
48 | SSH
49 | <% end %>
50 | <% if project.repository.extra[:git_http].to_s != "0" %>
51 | HTTP
52 | <% end %>
53 | <% if project.is_public && project.repository.extra[:git_daemon].to_s != "0" %>
54 | Git
55 | <% end %>
56 |
57 |
58 |
This URL has Read-Only access.
59 |
60 |
61 | <% end %>
62 | <% end %>
63 |
--------------------------------------------------------------------------------
/app/views/repositories/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= error_messages_for 'repository' %>
2 |
3 | <% content_for :header_tags do %>
4 | <%= stylesheet_link_tag('application', :plugin => 'redmine_git_hosting') %>
5 | <%= stylesheet_link_tag('modalbox/modalbox', :plugin => 'redmine_git_hosting') %>
6 | <%= javascript_include_tag('modalbox/modalbox', :plugin => 'redmine_git_hosting') %>
7 | <% end %>
8 |
9 |
10 | <% if @repository && @repository.is_a?(Repository::Git) && (GitHostingHelper.can_view_deployment_keys(@repository.project) || GitHostingHelper.can_view_post_receive_urls(@repository.project) || GitHostingHelper.can_view_mirrors(@repository.project)) %>
11 |
Repository Options
12 | <% end %>
13 |
14 |
15 | <%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %>
16 | <% if @repository && ! @repository.class.scm_available %>
17 | <%= l(:text_scm_command_not_available) %>
18 | <% end %>
19 |
20 |
21 |
<%= f.check_box :is_default, :label => :field_repository_is_default %>
22 | <% if @repository && @repository.is_a?(Repository::Git) %>
23 |
<%= f.text_field :identifier, :label => (@repository.new_record? ? :field_identifier : :label_identifier_cannot_be_changed), :disabled => !@repository.new_record? %>
24 | <% else %>
25 |
<%= f.text_field :identifier %>
26 | <% end %>
27 |
28 | <% button_disabled = true %>
29 | <% if @repository %>
30 | <% button_disabled = ! @repository.class.scm_available %>
31 | <% end %>
32 |
33 | <% if @repository && @repository.is_a?(Repository::Git) %>
34 |
35 | <%= label_tag "extra[git_daemon]", l(:field_git_daemon) %>
36 | <%= select_tag "extra[git_daemon]", options_for_select([ [l(:label_disabled), "0"], [l(:label_enabled), "1"]], :selected=>(@project.is_public ? @repository.extra[:git_daemon].to_s : "0")), :disabled => !@project.is_public %>
37 |
38 |
39 | <%= label_tag "extra[git_http]", l(:field_git_http) %>
40 | <%= select_tag "extra[git_http]", options_for_select([ [l(:label_disabled), "0"], [l(:label_https_only), "1"], [l(:label_https_and_http), "2"] ], :selected=>@repository.extra[:git_http].to_s) %>
41 |
42 |
43 | <%= label_tag "extra[notify_cia]", l(:field_notify_cia) %>
44 | <%= select_tag "extra[notify_cia]", options_for_select([ [l(:label_disabled), "0"], [l(:label_enabled), "1"]], :selected=>@repository.extra[:notify_cia].to_s) %>
45 | <% if @repository.extra[:notify_cia].to_s == "1" %>
46 | "test", :projectid => @repository.project.identifier) %>"><%= l(:field_notify_cia_test) %>
47 |
48 | <% end %>
49 |
50 | <%= javascript_include_tag('notify_cia_test', :plugin => 'redmine_git_hosting') %>
51 |
52 | <% else %>
53 | <%= repository_field_tags(f, @repository) if @repository %>
54 | <% end %>
55 |
56 | <%= submit_tag(@repository.new_record? ? l(:button_create) : l(:button_save), :disabled => button_disabled) %>
57 | <%= link_to l(:button_cancel), settings_project_path(@project, :tab => 'repositories') %>
58 |
59 |
--------------------------------------------------------------------------------
/selinux/redmine_git.te:
--------------------------------------------------------------------------------
1 | policy_module(redmine_git,1.0.0)
2 |
3 | ########################################
4 | #
5 | # Declarations
6 | #
7 | require {
8 | type httpd_t, httpd_sys_script_t, httpd_sys_script_exec_t;
9 | type sudo_db_t;
10 | type httpd_redmine_git_script_t;
11 | type httpd_redmine_git_script_exec_t;
12 | type gitosis_var_lib_t;
13 | class process { setrlimit setfscreate };
14 | class netlink_route_socket { write getattr read bind create nlmsg_read };
15 | class capability { setuid sys_resource setgid };
16 | class dir { getattr search write write rename create reparent rmdir };
17 | class lnk_file unlink;
18 | }
19 |
20 | apache_content_template(redmine_git)
21 |
22 | permissive httpd_redmine_git_script_t;
23 |
24 | ########################################
25 | #
26 | # httpd_redmine_git_script local policy
27 | #
28 | ########################################
29 |
30 | manage_dirs_pattern(httpd_redmine_git_script_t, httpd_redmine_git_script_rw_t, httpd_redmine_git_script_rw_t)
31 | manage_files_pattern(httpd_redmine_git_script_t, httpd_redmine_git_script_rw_t, httpd_redmine_git_script_rw_t)
32 |
33 | domain_use_interactive_fds(httpd_redmine_git_script_t)
34 |
35 | files_read_etc_files(httpd_redmine_git_script_t)
36 |
37 | miscfiles_read_localization(httpd_redmine_git_script_t)
38 |
39 | # Allow our scripts to be called by redmine/apache
40 | httpd_redmine_git_script_domtrans(httpd_sys_script_t)
41 |
42 | # Allow us to access to rest of redmine site
43 | miscfiles_read_public_files(httpd_redmine_git_script_t)
44 | miscfiles_manage_public_files(httpd_redmine_git_script_t)
45 |
46 | #============= httpd_redmine_git_script_t ==============
47 | #Specific capabilities identified by audit2allow
48 |
49 | allow httpd_redmine_git_script_t self:capability audit_write;
50 | allow httpd_redmine_git_script_t self:capability { setuid sys_resource setgid };
51 | allow httpd_redmine_git_script_t self:key write;
52 | allow httpd_redmine_git_script_t self:netlink_audit_socket { write nlmsg_relay create read };
53 | allow httpd_redmine_git_script_t self:netlink_route_socket { write getattr read bind create nlmsg_read };
54 | allow httpd_redmine_git_script_t self:process setrlimit;
55 | allow httpd_redmine_git_script_t sudo_db_t:dir { getattr search };
56 |
57 | # Capabilities required to manage gitolite repositories
58 | allow httpd_redmine_git_script_t gitosis_var_lib_t:dir { rename create reparent rmdir };
59 | allow httpd_redmine_git_script_t gitosis_var_lib_t:lnk_file unlink;
60 | gitosis_read_lib_files(httpd_redmine_git_script_t)
61 | gitosis_manage_lib_files(httpd_redmine_git_script_t)
62 |
63 | apache_rw_stream_sockets(httpd_redmine_git_script_t)
64 | kernel_read_kernel_sysctls(httpd_redmine_git_script_t)
65 | logging_send_syslog_msg(httpd_redmine_git_script_t)
66 |
67 | # These seem to be needed for ssh.... Not sure why ssh needs
68 | # to read and/or validate contexts...
69 | allow httpd_redmine_git_script_t self:process setfscreate;
70 | miscfiles_manage_cert_dirs(httpd_redmine_git_script_t)
71 | miscfiles_manage_cert_files(httpd_redmine_git_script_t)
72 | selinux_load_policy(httpd_redmine_git_script_t)
73 | selinux_validate_context(httpd_redmine_git_script_t)
74 | seutil_read_file_contexts(httpd_redmine_git_script_t)
75 | seutil_search_default_contexts(httpd_redmine_git_script_t)
76 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | def install_redmine_git_hosting_routes(map)
2 | # URL for items of type httpServer/XXX.git. Some versions of rails has problems with multiple regex expressions, so avoid...
3 | # Note that 'http_server_subdir' is either empty (default case) or ends in '/'.
4 | map.connect ":repo_path/*path",
5 | :prefix => (Setting.plugin_redmine_git_hosting['httpServerSubdir'] rescue ""), :repo_path => /([^\/]+\/)*?[^\/]+\.git/, :controller => 'git_http'
6 |
7 | # Handle the public keys plugin to my/account.
8 | map.resources :public_keys, :controller => 'gitolite_public_keys', :path_prefix => 'my'
9 | map.connect 'my/account/public_key/:public_key_id', :controller => 'my', :action => 'account'
10 | map.connect 'users/:id/edit/public_key/:public_key_id', :controller => 'users', :action => 'edit', :conditions => {:method => [:get]}
11 |
12 | # Handle hooks and mirrors
13 | map.connect 'githooks', :controller => 'gitolite_hooks', :action => 'stub'
14 | map.connect 'githooks/post-receive', :controller => 'gitolite_hooks', :action => 'post_receive'
15 | map.connect 'githooks/test', :controller => 'gitolite_hooks', :action => 'test'
16 | map.with_options :controller => 'repositories' do |repo_mapper|
17 | repo_mapper.with_options :controller => 'repository_mirrors' do |mirror_views|
18 | mirror_views.connect 'repositories/:repository_id/mirrors/new', :action => 'create', :conditions => {:method => [:get, :post]}
19 | mirror_views.connect 'repositories/:repository_id/mirrors/edit/:id', :action => 'edit'
20 | mirror_views.connect 'repositories/:repository_id/mirrors/push/:id', :action => 'push'
21 | mirror_views.connect 'repositories/:repository_id/mirrors/update/:id', :action => 'update', :conditions => {:method => :post}
22 | mirror_views.connect 'repositories/:repository_id/mirrors/delete/:id', :action => 'destroy', :conditions => {:method => [:get, :delete]}
23 | end
24 | repo_mapper.with_options :controller => 'repository_post_receive_urls' do |post_receive_views|
25 | post_receive_views.connect 'repositories/:repository_id/post-receive-urls/new', :action => 'create', :conditions => {:method => [:get, :post]}
26 | post_receive_views.connect 'repositories/:repository_id/post-receive-urls/edit/:id', :action => 'edit'
27 | post_receive_views.connect 'repositories/:repository_id/post-receive-urls/update/:id', :action => 'update', :conditions => {:method => :post}
28 | post_receive_views.connect 'repositories/:repository_id/post-receive-urls/delete/:id', :action => 'destroy', :conditions => {:method => [:get, :delete]}
29 | end
30 | repo_mapper.with_options :controller => 'deployment_credentials' do |deploy_views|
31 | deploy_views.connect 'repositories/:repository_id/deployment-credentials/new', :action => 'create_with_key', :conditions => {:method => [:get, :post]}
32 | deploy_views.connect 'repositories/:repository_id/deployment-credentials/edit/:id', :action => 'edit'
33 | deploy_views.connect 'repositories/:repository_id/deployment-credentials/update/:id', :action => 'update', :conditions => {:method => :post}
34 | deploy_views.connect 'repositories/:repository_id/deployment-credentials/delete/:id', :action => 'destroy', :conditions => {:method => [:get, :delete]}
35 | end
36 | end
37 | end
38 |
39 | if defined? map
40 | install_redmine_git_hosting_routes(map)
41 | else
42 | ActionController::Routing::Routes.draw do |map|
43 | install_redmine_git_hosting_routes(map)
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/app/models/git_hosting_observer.rb:
--------------------------------------------------------------------------------
1 | class GitHostingObserver < ActiveRecord::Observer
2 | observe :project, :user, :gitolite_public_key, :member, :role, :repository
3 |
4 | @@updating_active = true
5 | @@updating_active_stack = 0
6 | @@updating_active_flags = {}
7 | @@cached_project_updates = []
8 |
9 | def reload_this_observer
10 | observed_classes.each do |klass|
11 | klass.name.constantize.add_observer(self)
12 | end
13 | end
14 |
15 |
16 | def self.set_update_active(*is_active)
17 | if !is_active || !is_active.first
18 | @@updating_active_stack += 1
19 | else
20 | is_active.each do |item|
21 | case item
22 | when Symbol then @@updating_active_flags[item] = true
23 | when Hash then @@updating_active_flags.merge!(item)
24 | when Project then @@cached_project_updates |= [item]
25 | end
26 | end
27 |
28 | # If about to transition to zero and have something to run, do it
29 | if @@updating_active_stack == 1 && (@@cached_project_updates.length > 0 || !@@updating_active_flags.empty?)
30 | @@cached_project_updates = @@cached_project_updates.flatten.uniq.compact
31 | GitHosting::update_repositories(@@cached_project_updates, @@updating_active_flags)
32 | @@cached_project_updates = []
33 | @@updating_active_flags = {}
34 | end
35 |
36 | # Wait until after running update_repositories before releasing
37 | @@updating_active_stack -= 1
38 | if @@updating_active_stack < 0
39 | @@updating_active_stack = 0
40 | end
41 | end
42 | @@updating_active = (@@updating_active_stack == 0)
43 | end
44 |
45 | # Register args for updating and then do it without allowing recursive calls
46 | def self.bracketed_update_repositories(*args)
47 | set_update_active(false)
48 | set_update_active(*args)
49 | end
50 |
51 | def after_create(object)
52 | if not object.is_a?(Project)
53 | update_repositories(object)
54 | end
55 | end
56 |
57 |
58 | def before_save(object)
59 | if object.is_a?(Repository::Git)
60 | GitHosting.logger.debug "On GitHostingObserver.before_save for Repository::Git"
61 | end
62 | end
63 |
64 |
65 | def after_save(object)
66 | update_repositories(object)
67 | end
68 |
69 |
70 | def after_destroy(object)
71 | if object.is_a?(Repository::Git)
72 | update_repositories(object,:delete=>true)
73 | CachedShellRedirector::clear_cache_for_repository(object)
74 | else
75 | update_repositories(object)
76 | end
77 | end
78 |
79 |
80 | protected
81 |
82 | def update_repositories(object,*flags)
83 | projects = []
84 | case object
85 | when Repository::Git then projects.push(object.project)
86 | when User then projects = object.projects unless is_login_save?(object)
87 | when GitolitePublicKey then projects = object.user.projects
88 | when Member then projects.push(object.project)
89 | when Role then projects = object.members.map(&:project).flatten.uniq.compact
90 | end
91 | if (projects.length > 0)
92 | if (@@updating_active)
93 | GitHosting::update_repositories(projects,*flags)
94 | else
95 | @@cached_project_updates.concat(projects)
96 | @@updating_active_flags.merge!(*flags) unless flags.empty?
97 | end
98 | end
99 | end
100 |
101 |
102 | # Test for the fingerprint of changes to the user model when the User actually logs in.
103 | def is_login_save?(user)
104 | user.changed? && user.changed.length == 2 && user.changed.include?("updated_on") && user.changed.include?("last_login_on")
105 | end
106 | end
107 |
--------------------------------------------------------------------------------
/selinux/README:
--------------------------------------------------------------------------------
1 | This directory contains a selinux policy crafted to cover the sudo and
2 | ssh scripts for the redmine_git_hosting plugin. In it, we define a new
3 | httpd-compatible type, "httpd_redmine_git_script_exec_t" which can be
4 | placed on the redmine_git_hosting/bin directory to allow sudo access
5 | from redmine code. The basic assumption is that scripts placed into
6 | this directory will be called from context "httpd_script_t" (i.e
7 | redmine).
8 |
9 | Once this plugin is placed under selinux control, three of the
10 | redmine_git_hosting settings can no longer be modified from the
11 | settings page. They are: 'gitUser', 'gitoliteIdentityFile', and
12 | 'gitoliteIdentityPublicKeyFile'. The plugin settings page will make
13 | this clear. The simplest way to modify these options is to
14 | temporarily place your system into permissive mode, refresh the
15 | setting page, change options, then place your system back into
16 | enforcing mode. Alternatively, you can alter the init.rb file and
17 | reinstall the plugin. Under normal operation, you will get one
18 | selinux complaint about /bin/touch in your log each time that you
19 | visit the plugin settings page.
20 |
21 | ******************* INSTALLATION AND SETUP *************************
22 | Note that the redmine_git_hosting/bin directory must be constructed
23 | statically so that it can be labeled. You can do this with a series
24 | of rake tasks at the top-level of the redmine directory (after fixing
25 | up the defaults in the redmine_git_hosting init.rb file):
26 |
27 | # Build bin directory with customized scripts for redmine_git_hosting,
28 | # install new selinux policy, and install complete selinux context for
29 | # redmine+this plugin:
30 |
31 | rake selinux:install RAILS_ENV=production
32 |
33 | Since redmine doesn't currently have a selinux install option, this
34 | installation command is only available for this plugin. What this
35 | will do is label the whole redmine site with "public_content_rw_t",
36 | with the exception of the "dispatch*" files in public (set to
37 | "httpd_script_exec_t") and the scripts in redmine_git_hosting/bin (set
38 | to "httpd_redmine_git_script_exec_t").
39 |
40 | If you happen to have multiple redmine installations, you can use a
41 | regular expression to describe the redmine root directories (this will
42 | translate into file context descriptions). For instance, if you have
43 | multiple redmine installations in directories whose paths start with
44 | "/source" and end with "redmine" you can use (notice the use of
45 | double-quotes!):
46 |
47 | rake selinux:install RAILS_ENV=production ROOT_PATTERN="/source/.*/redmine"
48 |
49 | Somewhat less far-reaching options include:
50 |
51 | # Build bin directory with customized scripts for redmine_git_hosting,
52 | # install new selinux policy, and install selinux context for
53 | # the redmine_git_hosting plugin
54 |
55 | rake selinux:redmine_git_hosting:install RAILS_ENV=production
56 |
57 | For those who are hand-crafting their own file context:
58 |
59 | # Build bin directory with customized scripts for redmine_git_hosting
60 | # and install new selinux policy. No file contexts will be
61 | # installed (so that you must do customization afterwards).
62 |
63 | rake selinux:redmine_git_hosting:install_scripts_and_policy RAILS_ENV=production
64 |
65 | Finally, to rebuild the policy file (redmine_git.pp) from source (redmine_git.te),
66 | you can type:
67 |
68 | # Rebuild redmine_git_hosting selinux policy from source
69 |
70 | rake selinux:redmine_git_hosting:build_policy RAILS_ENV=production
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/selinux/redmine_git.if:
--------------------------------------------------------------------------------
1 |
2 | ## policy for httpd_redmine_git_script
3 |
4 |
5 | ########################################
6 | ##
7 | ## Execute a domain transition to run httpd_redmine_git_script.
8 | ##
9 | ##
10 | ##
11 | ## Domain allowed access.
12 | ##
13 | ##
14 | #
15 | interface(`httpd_redmine_git_script_domtrans',`
16 | gen_require(`
17 | type httpd_redmine_git_script_t, httpd_redmine_git_script_exec_t;
18 | ')
19 |
20 | domtrans_pattern($1, httpd_redmine_git_script_exec_t, httpd_redmine_git_script_t)
21 | ')
22 |
23 |
24 | ########################################
25 | ##
26 | ## Search httpd_redmine_git_script rw directories.
27 | ##
28 | ##
29 | ##
30 | ## Domain allowed access.
31 | ##
32 | ##
33 | #
34 | interface(`httpd_redmine_git_script_search_rw_dir',`
35 | gen_require(`
36 | type httpd_redmine_git_script_rw_t;
37 | ')
38 |
39 | allow $1 httpd_redmine_git_script_rw_t:dir search_dir_perms;
40 | files_search_rw($1)
41 | ')
42 |
43 | ########################################
44 | ##
45 | ## Read httpd_redmine_git_script rw files.
46 | ##
47 | ##
48 | ##
49 | ## Domain allowed access.
50 | ##
51 | ##
52 | #
53 | interface(`httpd_redmine_git_script_read_rw_files',`
54 | gen_require(`
55 | type httpd_redmine_git_script_rw_t;
56 | ')
57 |
58 | allow $1 httpd_redmine_git_script_rw_t:file r_file_perms;
59 | allow $1 httpd_redmine_git_script_rw_t:dir list_dir_perms;
60 | files_search_rw($1)
61 | ')
62 |
63 | ########################################
64 | ##
65 | ## Create, read, write, and delete
66 | ## httpd_redmine_git_script rw files.
67 | ##
68 | ##
69 | ##
70 | ## Domain allowed access.
71 | ##
72 | ##
73 | #
74 | interface(`httpd_redmine_git_script_manage_rw_files',`
75 | gen_require(`
76 | type httpd_redmine_git_script_rw_t;
77 | ')
78 |
79 | manage_files_pattern($1, httpd_redmine_git_script_rw_t, httpd_redmine_git_script_rw_t)
80 | ')
81 |
82 | ########################################
83 | ##
84 | ## Create, read, write, and delete
85 | ## httpd_redmine_git_script rw dirs.
86 | ##
87 | ##
88 | ##
89 | ## Domain allowed access.
90 | ##
91 | ##
92 | #
93 | interface(`httpd_redmine_git_script_manage_rw_dirs',`
94 | gen_require(`
95 | type httpd_redmine_git_script_rw_t;
96 | ')
97 |
98 | manage_dirs_pattern($1, httpd_redmine_git_script_rw_t, httpd_redmine_git_script_rw_t)
99 | ')
100 |
101 |
102 | ########################################
103 | ##
104 | ## All of the rules required to administrate
105 | ## an httpd_redmine_git_script environment
106 | ##
107 | ##
108 | ##
109 | ## Domain allowed access.
110 | ##
111 | ##
112 | ##
113 | ##
114 | ## Role allowed access.
115 | ##
116 | ##
117 | ##
118 | #
119 | interface(`httpd_redmine_git_script_admin',`
120 | gen_require(`
121 | type httpd_redmine_git_script_t;
122 | type httpd_redmine_git_script_rw_t;
123 | ')
124 |
125 | allow $1 httpd_redmine_git_script_t:process { ptrace signal_perms };
126 | ps_process_pattern($1, httpd_redmine_git_script_t)
127 |
128 | files_search_etc($1)
129 | admin_pattern($1, httpd_redmine_git_script_rw_t)
130 |
131 | ')
132 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/git_adapter_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'redmine/scm/adapters/git_adapter'
5 |
6 | module GitHosting
7 | module Patches
8 | module GitAdapterPatch
9 |
10 | def self.included(base)
11 | base.class_eval do
12 | unloadable
13 | end
14 |
15 | begin
16 | base.send(:alias_method_chain, :git_cmd, :sudo)
17 | rescue
18 | # Hm... might be pre-1.4, where :git_cmd => :scm_cmd
19 | base.send(:alias_method_chain, :scm_cmd, :sudo) rescue nil
20 | base.send(:alias_method, :git_cmd, :git_cmd_with_sudo)
21 | end
22 |
23 | base.extend(ClassMethods)
24 | base.class_eval do
25 | class << self
26 | begin
27 | alias_method_chain :sq_bin, :sudo
28 | begin
29 | alias_method_chain :client_command, :sudo
30 | rescue Exception =>e
31 | end
32 | rescue Exception => e
33 | # Hm.... Might be Redmine version < 1.2 (i.e. 1.1). Try redefining GIT_BIN.
34 | GitHosting.logger.warn "Seems to be early version of Redmine(1.1?), try redefining GIT_BIN."
35 | Redmine::Scm::Adapters::GitAdapter::GIT_BIN = GitHosting::git_exec()
36 | end
37 | end
38 | end
39 | end
40 |
41 | module ClassMethods
42 | def sq_bin_with_sudo
43 | return Redmine::Scm::Adapters::GitAdapter::shell_quote(GitHosting::git_exec())
44 | end
45 | def client_command_with_sudo
46 | return GitHosting::git_exec()
47 | end
48 | end
49 |
50 | # Pre-1.4 command syntax
51 | def scm_cmd_with_sudo(*args, &block)
52 | git_cmd_with_sudo(args, &block)
53 | end
54 |
55 | # Post-1.4 command syntax
56 | def git_cmd_with_sudo(args, options = {}, &block)
57 | repo_path = root_url || url
58 | full_args = [GitHosting::git_exec(), '--git-dir', repo_path]
59 | if self.class.client_version_above?([1, 7, 2])
60 | full_args << '-c' << 'core.quotepath=false'
61 | full_args << '-c' << 'log.decorate=no'
62 | end
63 | full_args += args
64 |
65 | cmd_str=full_args.map { |e| shell_quote e.to_s }.join(' ')
66 |
67 | # Compute string from repo_path that should be same as: repo.git_label(:assume_unique=>false)
68 | # If only we had access to the repo (we don't).
69 | repo_id=Repository.repo_path_to_git_label(repo_path)
70 |
71 | # Insert cache between shell execution and caller
72 | # repo_path argument used to identify cache entries
73 | CachedShellRedirector.execute(cmd_str,repo_id,options,&block)
74 | end
75 |
76 | # Check for latest commit (applied to this repo) and set it as a
77 | # limit for the oldest cached entries. This caused cached entries
78 | # to be ignored/invalidated if they are older than the latest log
79 | # entry
80 | def ignore_old_cache_entries
81 | Rails.logger.error "Running ignore_old_cache_entries"
82 | # Ask for latest "commit date" on all branches
83 | cmd_args = %w|log --all --date=iso --format=%cd -n 1 --date=iso|
84 | begin
85 | git_cmd(cmd_args,:uncached=>true) do |io|
86 | # Register this latest commit time as cache limit time
87 | limit=Time.parse(io.readline)
88 | CachedShellRedirector.limit_cache(root_url||url,limit)
89 | end
90 | rescue
91 | # Wasn't able to ask git for limit date. Just disable cache.
92 | CachedShellRedirector.clear_cache_for_repository(root_url||url)
93 | end
94 | end
95 | end
96 | end
97 | end
98 |
99 | # Patch in changes
100 | Redmine::Scm::Adapters::GitAdapter.send(:include, GitHosting::Patches::GitAdapterPatch)
101 |
--------------------------------------------------------------------------------
/app/views/projects/settings/_repository.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :header_tags do %>
2 | <%= stylesheet_link_tag('application', :plugin => 'redmine_git_hosting') %>
3 | <%= stylesheet_link_tag('modalbox/modalbox', :plugin => 'redmine_git_hosting') %>
4 | <%= javascript_include_tag('modalbox/modalbox', :plugin => 'redmine_git_hosting') %>
5 | <% end %>
6 |
7 | <% labelled_remote_form_for :repository, @repository, :url => { :controller => 'repositories', :action => 'edit', :id => @project } do |f| %>
8 | <%= error_messages_for 'repository' %>
9 |
10 |
11 | <% if @repository && @repository.is_a?(Repository::Git) && (GitHostingHelper.can_view_deployment_keys(@repository.project) || GitHostingHelper.can_view_post_receive_urls(@repository.project) || GitHostingHelper.can_view_mirrors(@repository.project)) %>
12 |
Repository Options
13 | <% end %>
14 |
15 |
<%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %>
16 |
17 | <% if @repository && @repository.is_a?(Repository::Git) %>
18 |
19 | <%= label_tag "extra[git_daemon]", l(:field_git_daemon) %>
20 | <%= select_tag "extra[git_daemon]", options_for_select([ [l(:label_disabled), "0"], [l(:label_enabled), "1"]], :selected=>(@project.is_public ? @repository.extra[:git_daemon].to_s : "0")), :disabled => !@project.is_public %>
21 |
22 |
23 | <%= label_tag "extra[git_http]", l(:field_git_http) %>
24 | <%= select_tag "extra[git_http]", options_for_select([ [l(:label_disabled), "0"], [l(:label_https_only), "1"], [l(:label_https_and_http), "2"] ], :selected=>@repository.extra[:git_http].to_s) %>
25 |
26 |
27 | <%= label_tag "extra[notify_cia]", l(:field_notify_cia) %>
28 | <%= select_tag "extra[notify_cia]", options_for_select([ [l(:label_disabled), "0"], [l(:label_enabled), "1"]], :selected=>@repository.extra[:notify_cia].to_s) %>
29 | <% if @repository.extra[:notify_cia].to_s == "1" %>
30 | "test", :projectid => @repository.project.identifier) %>"><%= l(:field_notify_cia_test) %>
31 |
32 | <% end %>
33 |
34 | <%= javascript_include_tag('notify_cia_test', :plugin => 'redmine_git_hosting') %>
35 |
36 | <% else %>
37 | <%= repository_field_tags(f, @repository) if @repository %>
38 | <% end %>
39 |
40 | <% if @repository && !@repository.new_record? %>
41 | <%= link_to(l(:label_user_plural), {:controller => 'repositories', :action => 'committers', :id => @project}, :class => 'icon icon-user') %>
42 | <%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project}, :confirm => l(:text_are_you_sure),:method => :post,:class => 'icon icon-del') %>
43 | <% end %>
44 |
45 | <%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save), :disabled => @repository.nil?) %>
46 |
47 | <% end %>
48 |
49 | <% if @repository && @repository.is_a?(Repository::Git) && !(@repository.nil? || @repository.new_record?) %>
50 | <% if GitHostingHelper.can_view_deployment_keys(@repository.project) %>
51 | <%= render :partial => 'deployment_credentials/view_list' %>
52 | <% end %>
53 |
54 | <% if GitHostingHelper.can_view_post_receive_urls(@repository.project) %>
55 | <%= render :partial => 'repository_post_receive_urls/view_list' %>
56 | <% end %>
57 |
58 | <% if GitHostingHelper.can_view_mirrors(@repository.project) %>
59 | <%= render :partial => 'repository_mirrors/view_list' %>
60 | <% end %>
61 | <% end %>
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/views/repository_post_receive_urls/_view_list.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% if GitHostingHelper.can_create_post_receive_urls(@repository.project) %>
4 |
5 | <%= link_to("Add Post Receive URL", url_for(:controller => 'repository_post_receive_urls', :action => 'create', :repository_id => @repository.id), :class => 'icon icon-add add-post-receive-url' ) %>
6 |
7 | <% end %>
8 |
9 |
Post Receive URLs
10 |
11 | <% if @repository.repository_post_receive_urls.any? %>
12 |
37 | <% else %>
38 |
39 | No Post Receive URLs Defined
40 |
41 | <% end %>
42 |
43 |
44 |
98 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/users_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'users_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module UsersControllerPatch
9 | def create_with_disable_update
10 | # Turn of updates during repository update
11 | GitHostingObserver.set_update_active(false);
12 |
13 | # Do actual update
14 | create_without_disable_update
15 |
16 | # Reenable updates to perform a single update
17 | GitHostingObserver.set_update_active(true);
18 | end
19 | def update_with_disable_update
20 | # Turn of updates during repository update
21 | GitHostingObserver.set_update_active(false);
22 |
23 | # Set public key values for view
24 | set_public_key_values
25 |
26 | # Do actual update
27 | update_without_disable_update
28 |
29 | # Reenable updates to perform a single update
30 | GitHostingObserver.set_update_active(true);
31 | end
32 | def destroy_with_disable_update
33 | # Turn of updates during repository update
34 | GitHostingObserver.set_update_active(false);
35 |
36 | # Do actual update
37 | destroy_without_disable_update
38 |
39 | # Reenable updates to perform a single update
40 | GitHostingObserver.set_update_active(:delete);
41 | end
42 | def edit_membership_with_disable_update
43 | # Turn of updates during repository update
44 | GitHostingObserver.set_update_active(false);
45 |
46 | # Do actual update
47 | edit_membership_without_disable_update
48 |
49 | # Reenable updates to perform a single update
50 | GitHostingObserver.set_update_active(true);
51 | end
52 | def destroy_membership_with_disable_update
53 | # Turn of updates during repository update
54 | GitHostingObserver.set_update_active(false);
55 |
56 | # Do actual update
57 | destroy_membership_without_disable_update
58 |
59 | # Reenable updates to perform a single update
60 | GitHostingObserver.set_update_active(true);
61 | end
62 |
63 | # Add in values for viewing public keys:
64 | def edit_with_public_keys
65 | # Set public key values for view
66 | set_public_key_values
67 |
68 | # Previous routine
69 | edit_without_public_keys
70 | end
71 |
72 | # Add in values for viewing public keys:
73 | def set_public_key_values
74 | @gitolite_user_keys = @user.gitolite_public_keys.active.user_key.find(:all,:order => 'title ASC, created_at ASC')
75 | @gitolite_deploy_keys = @user.gitolite_public_keys.active.deploy_key.find(:all,:order => 'title ASC, created_at ASC')
76 | @gitolite_public_keys = @gitolite_user_keys + @gitolite_deploy_keys
77 | @gitolite_public_key = @gitolite_public_keys.detect{|x| x.id == params[:public_key_id].to_i}
78 | if @gitolite_public_key.nil?
79 | if params[:public_key_id]
80 | # public_key specified that doesn't belong to @user. Kill off public_key_id and try again
81 | redirect_to :public_key_id => nil, :tab => nil
82 | return
83 | else
84 | @gitolite_public_key = GitolitePublicKey.new
85 | end
86 | end
87 | end
88 |
89 | def self.included(base)
90 | base.class_eval do
91 | unloadable
92 |
93 | helper :gitolite_public_keys
94 | end
95 | # Edit adds new functionality, so don't silently fail!
96 | base.send(:alias_method_chain, :edit, :public_keys)
97 | begin
98 | base.send(:alias_method_chain, :create, :disable_update)
99 | base.send(:alias_method_chain, :update, :disable_update)
100 | base.send(:alias_method_chain, :edit_membership, :disable_update)
101 | base.send(:alias_method_chain, :destroy_membership, :disable_update)
102 | # Put this last, since Redmine 1.1 doesn't have it....
103 | base.send(:alias_method_chain, :destroy, :disable_update)
104 | rescue
105 | end
106 | end
107 | end
108 | end
109 | end
110 |
111 | # Patch in changes
112 | UsersController.send(:include, GitHosting::Patches::UsersControllerPatch)
113 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/members_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'members_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module MembersControllerPatch
9 | # pre-1.4 (Non RESTfull)
10 | def new_with_disable_update
11 | # Turn of updates during repository update
12 | GitHostingObserver.set_update_active(false);
13 |
14 | # Do actual update
15 | new_without_disable_update
16 |
17 | # Reenable updates to perform a single update
18 | GitHostingObserver.set_update_active(true);
19 | end
20 | # post-1.4 (RESTfull)
21 | def create_with_disable_update
22 | # Turn of updates during repository update
23 | GitHostingObserver.set_update_active(false);
24 |
25 | # Do actual update
26 | create_without_disable_update
27 |
28 | # Reenable updates to perform a single update
29 | GitHostingObserver.set_update_active(true);
30 | end
31 | # pre-1.4 (Non RESTfull)
32 | def edit_with_disable_update
33 | # Turn of updates during repository update
34 | GitHostingObserver.set_update_active(false);
35 |
36 | # Do actual update
37 | edit_without_disable_update
38 |
39 | # Reenable updates to perform a single update
40 | GitHostingObserver.set_update_active(true);
41 | end
42 | # post-1.4 (RESTfull)
43 | def update_with_disable_update
44 | # Turn of updates during repository update
45 | GitHostingObserver.set_update_active(false);
46 |
47 | # Do actual update
48 | update_without_disable_update
49 |
50 | # Reenable updates to perform a single update
51 | GitHostingObserver.set_update_active(true);
52 | end
53 | def destroy_with_disable_update
54 | # Turn of updates during repository update
55 | GitHostingObserver.set_update_active(false);
56 |
57 | # Do actual update
58 | destroy_without_disable_update
59 |
60 | # Reenable updates to perform a single update
61 | GitHostingObserver.set_update_active(:delete => true);
62 | end
63 |
64 | # Need to make sure that we can re-render the repository settings page
65 | # (Only for pre-1.4, i.e. single repo/project)
66 | def render_with_trigger_refresh(*options, &myblock)
67 | doing_update = options.detect {|x| x==:update || (x.is_a?(Hash) && x[:update])}
68 | if !doing_update
69 | render_without_trigger_refresh(*options, &myblock)
70 | else
71 | # For repository partial
72 | render_without_trigger_refresh *options do |page|
73 | yield page
74 | if (@repository ||= @project.repository) && (@repository.is_a?(Repository::Git))
75 | page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
76 | end
77 | end
78 | end
79 | end
80 |
81 | def self.included(base)
82 | base.class_eval do
83 | unloadable
84 |
85 | helper :repositories
86 | end
87 | begin
88 | # RESTfull (post-1.4)
89 | base.send(:alias_method_chain, :create, :disable_update)
90 | rescue
91 | # Not RESTfull (pre-1.4)
92 | base.send(:alias_method_chain, :new, :disable_update) rescue nil
93 | end
94 | begin
95 | # RESTfull (post-1.4)
96 | base.send(:alias_method_chain, :update, :disable_update)
97 | rescue
98 | # Not RESTfull (pre-1.4)
99 | base.send(:alias_method_chain, :edit, :disable_update) rescue nil
100 | end
101 | base.send(:alias_method_chain, :destroy, :disable_update) rescue nil
102 |
103 | # This patch only needed when repository settings in same set
104 | # if tabs as members (i.e. pre-1.4, single repo)
105 | # (Note that patches not stabilized yet, so cannot just call:
106 | # Project.multi_repos?
107 | if !GitHosting.multi_repos?
108 | base.send(:alias_method_chain, :render, :trigger_refresh) rescue nil
109 | end
110 | end
111 | end
112 | end
113 | end
114 |
115 | # Patch in changes
116 | MembersController.send(:include, GitHosting::Patches::MembersControllerPatch)
117 |
--------------------------------------------------------------------------------
/contrib/hooks/post-receive.redmine_gitolite.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'digest/sha1'
4 | require 'net/http'
5 | require 'net/https'
6 | require 'uri'
7 |
8 | STDOUT.sync=true
9 | $debug=false
10 |
11 |
12 | def log(msg, debug_only=false, with_newline=true)
13 | if $debug || (!debug_only)
14 | print msg + (with_newline ? "\n" : "")
15 | end
16 | end
17 | def get_git_repository_config(varname)
18 | (%x[git config #{varname} ]).chomp.strip
19 | end
20 | def get_http_params(rgh_vars)
21 | clear_time = Time.new.utc.to_i.to_s
22 | params = { "clear_time" => clear_time, "encoded_time" => Digest::SHA1.hexdigest(clear_time.to_s + rgh_vars["key"]) }
23 | rgh_vars.each_key do |v|
24 | if v != "key"
25 | params[v] = rgh_vars[v]
26 | end
27 | end
28 | params
29 | end
30 |
31 | # Need to do this ourselves, because 1.8.7 ruby is broken
32 | def set_form_data(request, params, sep = '&')
33 | request.body = params.map {|k,v|
34 | if v.instance_of?(Array)
35 | v.map {|e| "#{urlencode(k.to_s)}=#{urlencode(e.to_s)}"}.join(sep)
36 | else
37 | "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}"
38 | end
39 | }.join(sep)
40 |
41 | request.content_type = 'application/x-www-form-urlencoded'
42 | end
43 |
44 | def urlencode(str)
45 | URI.encode(str,/[^a-zA-Z0-9_\.\-]/)
46 | end
47 |
48 | def run_query(url_str, params, with_https)
49 | url_str = (with_https ? "https://" : "http://" ) + url_str.gsub(/^http[s]*:\/\//, "")
50 | success = false
51 | begin
52 | url = URI.parse(url_str)
53 | http = Net::HTTP.new( url.host, url.port )
54 | http.open_timeout = 20
55 | http.read_timeout = 180
56 | if with_https
57 | http.use_ssl = true
58 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
59 | end
60 | req = Net::HTTP::Post.new(url.request_uri)
61 | set_form_data(req,params)
62 | response = http.request(req) do |response|
63 | response.read_body do |body_frag|
64 | success = response.code.to_i == 200 ? true : false
65 | log(body_frag, false, false)
66 | end
67 | end
68 | #response = http.request(req)
69 | #puts response.header
70 | rescue Exception =>e
71 | #log("HTTP_ERROR:" + e.to_s, true, true)
72 | success = false
73 | end
74 | success
75 | end
76 |
77 |
78 |
79 |
80 | rgh_vars = {}
81 | rgh_var_names = [ "hooks.redmine_gitolite.key", "hooks.redmine_gitolite.url", "hooks.redmine_gitolite.projectid", "hooks.redmine_gitolite.repositoryid", "hooks.redmine_gitolite.debug", "hooks.redmine_gitolite.asynch"]
82 | rgh_var_names.each do |var_name|
83 | var_val = get_git_repository_config(var_name)
84 | if var_val.to_s == ""
85 | # Allow blank repositoryID (as default)
86 | if var_name != "hooks.redmine_gitolite.repositoryid"
87 | log("\n\nRepository does not have \"#{var_name}\" set. Skipping hook.\n\n", false, true)
88 | exit
89 | end
90 | else
91 | var_name = var_name.gsub(/^.*\./, "")
92 | rgh_vars[ var_name ] = var_val
93 | end
94 | end
95 |
96 | $debug = rgh_vars["debug"] == "true"
97 |
98 |
99 | # Let's read the refs passed to us
100 | refs = []
101 | $<.each do |line|
102 | r = line.chomp.strip.split
103 | refs.push( [ r[0].to_s, r[1].to_s, r[2].to_s ].join(",") )
104 | end
105 | rgh_vars["refs[]"] = refs
106 |
107 | if rgh_vars["asynch"] == "true"
108 | pid = fork
109 | exit unless pid.nil?
110 | pid = fork
111 | exit unless pid.nil?
112 |
113 | File.umask 0000
114 |
115 | STDIN.reopen '/dev/null'
116 | STDOUT.reopen '/dev/null', 'a'
117 | STDERR.reopen STDOUT
118 |
119 | end
120 |
121 | log("\n\n", false, true)
122 | log("Notifying ChiliProject/Redmine project #{rgh_vars['projectid']} about changes to this repo...", true, true)
123 | success = run_query(rgh_vars["url"], get_http_params(rgh_vars), true)
124 | if !success
125 | success = run_query(rgh_vars["url"], get_http_params(rgh_vars), false)
126 | end
127 | if(!success)
128 | log("Error contacting ChiliProject/Redmine about changes to this repo.", false, true)
129 | else
130 | log("Success", true, true)
131 | log("", true, true)
132 | end
133 | log("\n\n", false, true)
134 |
135 | exit
136 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/repositories_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'repositories_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module RepositoriesControllerPatch
9 | def show_with_git_instructions
10 | if @repository.is_a?(Repository::Git) and @repository.entries(@path, @rev).blank?
11 | # Fake list of repos
12 | @repositories = @project.all_repos
13 | render :action => 'git_instructions'
14 | else
15 | show_without_git_instructions
16 | end
17 | end
18 |
19 | # This patch is only for pre-1.4 Redmine (since they made this controller RESTful
20 | def edit_with_scm_settings
21 | GitHosting.logger.debug "On edit_with_scm_settings"
22 |
23 | # Turn off updates during repository update
24 | GitHostingObserver.set_update_active(false);
25 | params[:repository] ||= {}
26 |
27 | if params[:repository_scm] == "Git" && @project.repository
28 | params[:repository][:url] = GitHosting.repository_path(@project.repository)
29 | end
30 |
31 | if params[:repository_scm] == "Git" || @project.repository.is_a?(Repository::Git)
32 | #Evidently the ONLY way to update the repository.extra table is to basically copy/paste the existing controller code
33 | #the update line needs to go in the dead center of it.
34 | @repository = @project.repository
35 | if !@repository
36 | @repository = Repository.factory(params[:repository_scm])
37 | @repository.project = @project if @repository
38 | end
39 | if request.post? && @repository
40 | @repository.attributes = params[:repository]
41 | if !params[:extra].nil?
42 | @repository.extra.update_attributes(params[:extra])
43 | end
44 | @repository.save
45 | end
46 |
47 |
48 | render(:update) do |page|
49 | page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
50 | if @repository && !@project.repository
51 | @project.reload #needed to reload association
52 | page.replace_html "main-menu", render_main_menu(@project)
53 | end
54 | end
55 |
56 | if !@project.repository.nil?
57 | GitHostingObserver.bracketed_update_repositories(@project)
58 | end
59 | else
60 | edit_without_scm_settings
61 | end
62 |
63 | GitHostingObserver.set_update_active(true);
64 | end
65 |
66 | # Post-1.4, all creation is done by create (rather than edit)
67 | def create_with_scm_settings
68 | GitHostingObserver.set_update_active(false)
69 |
70 | # Must create repository first
71 | create_without_scm_settings
72 |
73 | if !@repository.errors.any?
74 | # Update repository extras
75 | if request.post? && @repository && !params[:extra].nil?
76 | @repository.extra.update_attributes(params[:extra])
77 | end
78 | GitHostingObserver.set_update_active(@project)
79 | else
80 | GitHostingObserver.set_update_active(true)
81 | end
82 | end
83 |
84 | # Post-1.4, all of the updates are done by update (rather than edit with post)
85 | def update_with_scm_settings
86 | GitHostingObserver.set_update_active(false)
87 |
88 | update_without_scm_settings
89 |
90 | if !@repository.errors.any?
91 | # Update repository extras
92 | if request.put? && @repository && !params[:extra].nil?
93 | @repository.extra.update_attributes(params[:extra])
94 | end
95 | GitHostingObserver.set_update_active(@project)
96 | else
97 | GitHostingObserver.set_update_active(true)
98 | end
99 | end
100 |
101 | def self.included(base)
102 | base.class_eval do
103 | unloadable
104 | end
105 | base.send(:alias_method_chain, :show, :git_instructions)
106 |
107 | # RESTful (post-1.4).
108 | base.send(:alias_method_chain, :create, :scm_settings) rescue nil
109 |
110 | begin
111 | # RESTfull (post-1.4)
112 | base.send(:alias_method_chain, :update, :scm_settings)
113 | rescue
114 | # Not RESTfull (pre-1.4)
115 | base.send(:alias_method_chain, :edit, :scm_settings) rescue nil
116 | end
117 | end
118 | end
119 | end
120 | end
121 |
122 | # Patch in changes
123 | RepositoriesController.send(:include, GitHosting::Patches::RepositoriesControllerPatch)
124 |
--------------------------------------------------------------------------------
/tasks/redmine_git_hosting.rake:
--------------------------------------------------------------------------------
1 | #
2 | # Tasks in this namespace (redmine_git_hosting) are for administrative tasks
3 | #
4 | # TOP-LEVEL TARGETS:
5 | #
6 | # 1) Repopulate settings in the database with defaults from init.rb
7 | #
8 | # rake redmine_git_hosting:restore_defaults RAILS_ENV=xxx
9 | #
10 | # 2) Resynchronize/repair gitolite configuration (fix keys directory and configuration).
11 | # Also, expire repositories in the recycle_bin if necessary.
12 | #
13 | # rake redmine_git_hosting:update_repositories RAILS_ENV=xxx
14 | #
15 | # 3) Fetch all changesets for repositories and then rescynronize gitolite configuration (as in #1)
16 | #
17 | # rake redmine_git_hosting:fetch_changsets RAILS_ENV=xxx
18 | #
19 | # 4) Install custom scripts to the script directory. The optional argument
20 | # 'READ_ONLY=true' requests that the resulting scripts and script directory
21 | # be made read-only to the web server. The optional argument WEB_USER=xxx
22 | # states that scripts should be owned by user "xxx". If omitted, the
23 | # script attempts to figure out the web user by using "ps" and looking
24 | # for httpd.
25 | #
26 | # rake redmine_git_hosting:install_scripts [READ_ONLY=true] [WEB_USER=xxx] RAILS_ENV=yyy
27 | #
28 | # 5) Remove the custom scripts directory (and the enclosed scripts)
29 | #
30 | # rake redmine_git_hosting:remove_scripts RAILS_ENV=xxxx
31 | #
32 | namespace :redmine_git_hosting do
33 | desc "Reload defaults from init.rb into the redmine_git_hosting settings."
34 | task :restore_defaults => [:environment] do
35 | if defined?(Rails) && Rails.logger
36 | Rails.logger.auto_flushing = true if Rails.logger.respond_to?(:auto_flushing=)
37 | Rails.logger.warn "\n\nReinitializing settings from init.rb (via rake at #{my_date})"
38 | end
39 | puts "[Reloading defaults from init.rb:"
40 | default_hash = Redmine::Plugin.find("redmine_git_hosting").settings[:default]
41 | if default_hash.nil? || default_hash.empty?
42 | puts " No defaults specified in init.rb!"
43 | else
44 | changes = 0
45 | valuehash = (Setting.plugin_redmine_git_hosting).clone
46 | default_hash.each do |key,value|
47 | if valuehash[key] != value
48 | print " Changing '#{key}': '#{valuehash[key]}' => '#{value}'\n"
49 | valuehash[key] = value
50 | changes += 1
51 | end
52 | end
53 | if changes == 0
54 | print " No changes necessary.\n"
55 | else
56 | print " Committing changes ... "
57 | begin
58 | Setting.plugin_redmine_git_hosting = valuehash
59 | print "Success!\n"
60 | rescue
61 | print "Failure.\n"
62 | end
63 | end
64 | end
65 | puts "DONE.]"
66 | end
67 |
68 | desc "Update/repair gitolite configuration"
69 | task :update_repositories => [:environment] do
70 | puts "[Performing manual update_repositories operation..."
71 | if defined?(Rails) && Rails.logger
72 | Rails.logger.auto_flushing = true if Rails.logger.respond_to?(:auto_flushing=)
73 | Rails.logger.warn "\n\nPerforming manual UpdateRepositories from command line (via rake at #{my_date})"
74 | end
75 | GitHosting.update_repositories(:resync_all => true)
76 | puts "DONE.]"
77 | end
78 |
79 | desc "Fetch commits from gitolite repositories/update gitolite configuration"
80 | task :fetch_changesets => [:environment] do
81 | puts "[Performing manual fetch_changesets operation..."
82 | if defined?(Rails) && Rails.logger
83 | Rails.logger.auto_flushing = true if Rails.logger.respond_to?(:auto_flushing=)
84 | Rails.logger.warn "\n\nPerforming manual FetchChangesets from command line (via rake at #{my_date})"
85 | end
86 | Repository.fetch_changesets
87 | puts "DONE.]"
88 | end
89 |
90 | desc "Install redmine_git_hosting scripts"
91 | task :install_scripts do |t,args|
92 | if !ENV["READ_ONLY"]
93 | ENV["READ_ONLY"] = "false"
94 | end
95 | Rake::Task["selinux:redmine_git_hosting:install_scripts"].invoke
96 | end
97 |
98 | desc "Remove redmine_git_hosting scripts"
99 | task :remove_scripts do
100 | Rake::Task["selinux:redmine_git_hosting:remove_scripts"].invoke
101 | end
102 | end
103 |
104 | # Produce date string of form used by redmine logs
105 | def my_date
106 | Time.now.strftime("%Y-%m-%d %H:%M:%S")
107 | end
108 |
--------------------------------------------------------------------------------
/app/helpers/git_hosting_helper.rb:
--------------------------------------------------------------------------------
1 | require "uri"
2 | require "net/http"
3 |
4 | module GitHostingHelper
5 |
6 | def self.git_daemon_enabled(repository, value)
7 | gd = 1
8 | if repository && !repository.extra.nil?
9 | gd = repository.extra[:git_daemon] ? repository.extra[:git_daemon] : gd
10 | end
11 | gd = repository.project.is_public ? gd : 0
12 | return return_selected_string(gd, value)
13 | end
14 |
15 | def self.git_http_enabled(repository, value)
16 | gh = 1
17 | if repository && !repository.extra.nil?
18 | gh = repository.extra[:git_http] ? repository.extra[:git_http] : gh
19 | end
20 | return return_selected_string(gh, value)
21 | end
22 |
23 | def self.git_notify_cia(repository, value)
24 | nc = 0
25 | if repository && !repository.extra.nil?
26 | nc = repository.extra[:notify_cia] ? repository.extra[:notify_cia] : nc
27 | end
28 | return return_selected_string(nc, value)
29 | end
30 |
31 | def self.return_selected_string(found_value, to_check_value)
32 | return "selected='selected'" if (found_value == to_check_value)
33 | return ""
34 | end
35 |
36 | def self.can_create_mirrors(project)
37 | return User.current.allowed_to?(:create_repository_mirrors, project)
38 | end
39 | def self.can_view_mirrors(project)
40 | return User.current.allowed_to?(:view_repository_mirrors, project)
41 | end
42 | def self.can_edit_mirrors(project)
43 | return User.current.allowed_to?(:edit_repository_mirrors, project)
44 | end
45 |
46 | def self.can_create_post_receive_urls(project)
47 | return User.current.allowed_to?(:create_repository_post_receive_urls, project)
48 | end
49 | def self.can_view_post_receive_urls(project)
50 | return User.current.allowed_to?(:view_repository_post_receive_urls, project)
51 | end
52 | def self.can_edit_post_receive_urls(project)
53 | return User.current.allowed_to?(:edit_repository_post_receive_urls, project)
54 | end
55 |
56 | def self.can_create_deployment_keys(project)
57 | return User.current.admin? || User.current.allowed_to?(:create_deployment_keys, project)
58 | end
59 | def self.can_view_deployment_keys(project)
60 | return User.current.admin? || User.current.allowed_to?(:view_deployment_keys, project)
61 | end
62 | def self.can_edit_deployment_keys(project)
63 | return User.current.admin? || User.current.allowed_to?(:edit_deployment_keys, project)
64 | end
65 | def self.can_create_deployment_keys_for_some_project(theuser=User.current)
66 | return true if theuser.admin?
67 | theuser.projects_by_role.each_key do |role|
68 | return true if role.allowed_to?(:create_deployment_keys)
69 | end
70 | false
71 | end
72 |
73 | @@file_actions = {
74 | "a" => "add",
75 | "m" => "modify",
76 | "r" => "remove",
77 | "d" => "remove"
78 | }
79 |
80 | @http_server = nil
81 |
82 | def url_for_revision(revision)
83 | rev = revision.respond_to?(:identifier) ? revision.identifier : revision
84 | shorten_url(
85 | url_for(:controller => 'repositories', :action => 'revision', :id => revision.project,
86 | :rev => rev, :only_path => false, :host => Setting['host_name'], :protocol => Setting['protocol']
87 | )
88 | )
89 | end
90 |
91 | def url_for_revision_path(revision, path)
92 | rev = revision.respond_to?(:identifier) ? revision.identifier : revision
93 | shorten_url(
94 | url_for(:controller => 'repositories', :action => 'entry', :id => revision.project,
95 | :rev => rev, :path => path, :only_path => false, :host => Setting['host_name'],
96 | :protocol => Setting['protocol']
97 | )
98 | )
99 | end
100 |
101 | def map_file_action(action)
102 | @@file_actions.fetch(action.downcase, action)
103 | end
104 |
105 | def shorten_url(url)
106 | if @http_server.nil?
107 | @uri = URI.parse("http://tinyurl.com/api-create.php")
108 | @http_server = Net::HTTP.new(@uri.host, @uri.port)
109 | @http_server.open_timeout = 1 # in seconds
110 | @http_server.read_timeout = 1 # in seconds
111 | end
112 | uri = @uri
113 | uri.query = "url=#{url}"
114 | request = Net::HTTP::Get.new(uri.request_uri)
115 | begin
116 | response = @http_server.request(request)
117 | GitHosting.logger.debug "Shortened URL is: #{response.body}"
118 | return response.body
119 | rescue Exception => e
120 | GitHosting.logger.warn "Failed to shorten url: #{e}"
121 | return url
122 | end
123 | end
124 |
125 | end
126 |
--------------------------------------------------------------------------------
/app/controllers/repository_post_receive_urls_controller.rb:
--------------------------------------------------------------------------------
1 | class RepositoryPostReceiveUrlsController < ApplicationController
2 | unloadable
3 |
4 | before_filter :require_login
5 | before_filter :set_user_variable
6 | before_filter :set_repository_variable
7 | before_filter :set_project_variable
8 | before_filter :check_required_permissions
9 | before_filter :check_xhr_request
10 | before_filter :find_repository_post_receive_url, :except => [:index, :create]
11 |
12 | menu_item :settings, :only => :settings
13 |
14 | layout Proc.new { |controller| controller.request.xhr? ? 'popup' : 'base' }
15 |
16 | def index
17 | render_404
18 | end
19 |
20 | def create
21 | @prurl = RepositoryPostReceiveUrl.new(params[:repository_post_receive_urls])
22 | if request.get?
23 | # display create view
24 | else
25 | @prurl.update_attributes(params[:repository_post_receive_urls])
26 | @prurl.repository = @repository
27 |
28 | if @prurl.save
29 | flash[:notice] = l(:post_receive_url_notice_created)
30 |
31 | redirect_url = success_url
32 | respond_to do |format|
33 | format.html {
34 | redirect_to redirect_url
35 | }
36 | format.js {
37 | render :update do |page|
38 | page.redirect_to redirect_url
39 | end
40 | }
41 | end
42 | else
43 | respond_to do |format|
44 | format.html {
45 | flash[:error] = l(:post_receive_url_notice_create_failed)
46 | render :action => "create"
47 | }
48 | format.js {
49 | render :action => "form_error"
50 | }
51 | end
52 | end
53 | end
54 | end
55 |
56 | def edit
57 | end
58 |
59 | def update
60 | if @prurl.update_attributes(params[:repository_post_receive_urls])
61 | flash[:notice] = l(:post_receive_url_notice_updated)
62 |
63 | redirect_url = success_url
64 | respond_to do |format|
65 | format.html {
66 | redirect_to redirect_url
67 | }
68 | format.js {
69 | render :update do |page|
70 | page.redirect_to redirect_url
71 | end
72 | }
73 | end
74 | else
75 | respond_to do |format|
76 | format.html {
77 | flash[:error] = l(:post_receive_url_notice_update_failed)
78 | render :action => "edit"
79 | }
80 | format.js {
81 | render :action => "form_error"
82 | }
83 |
84 | end
85 | end
86 | end
87 |
88 | def destroy
89 | if request.get?
90 | # display confirmation view
91 | else
92 | if params[:confirm]
93 | @prurl.destroy
94 |
95 | flash[:notice] = l(:post_receive_url_notice_deleted)
96 | end
97 |
98 | redirect_url = success_url
99 | respond_to do |format|
100 | format.html {
101 | redirect_to(redirect_url)
102 | }
103 | end
104 | end
105 | end
106 |
107 | def settings
108 | end
109 |
110 | protected
111 |
112 | # This is a success URL to return to basic listing
113 | def success_url
114 | if GitHosting.multi_repos?
115 | url_for(:controller => 'repositories',
116 | :action => 'edit',
117 | :id => @repository.id)
118 | else
119 | url_for(:controller => 'projects',
120 | :action => 'settings',
121 | :id => @project.id,
122 | :tab => 'repository')
123 | end
124 | end
125 |
126 | def set_user_variable
127 | @user = User.current
128 | end
129 |
130 | def set_repository_variable
131 | @repository = Repository.find_by_id(params[:repository_id])
132 | if !@repository
133 | render_404
134 | end
135 | end
136 |
137 | def set_project_variable
138 | @project = @repository.project
139 | if !@project
140 | render_404
141 | end
142 | end
143 |
144 | def find_repository_post_receive_url
145 | prurl = RepositoryPostReceiveUrl.find_by_id(params[:id])
146 |
147 | @prurls = @repository.repository_post_receive_urls
148 |
149 | if prurl and prurl.repository == @repository
150 | @prurl = prurl
151 | elsif prurl
152 | render_403
153 | else
154 | render_404
155 | end
156 | end
157 |
158 | def check_required_permissions
159 | # Deny access if the curreent user is not allowed to manage the project's repositoy
160 | if not @project.module_enabled?(:repository)
161 | render_403
162 | end
163 | not_enough_perms = true
164 | @user.roles_for_project(@project).each{|role|
165 | if role.allowed_to? :manage_repository
166 | not_enough_perms = false
167 | break
168 | end
169 | }
170 | if not_enough_perms
171 | render_403
172 | end
173 | end
174 |
175 | def check_xhr_request
176 | @is_xhr ||= request.xhr?
177 | end
178 |
179 | end
180 |
--------------------------------------------------------------------------------
/app/controllers/repository_mirrors_controller.rb:
--------------------------------------------------------------------------------
1 | class RepositoryMirrorsController < ApplicationController
2 | unloadable
3 |
4 | before_filter :require_login
5 | before_filter :set_user_variable
6 | before_filter :set_repository_variable
7 | before_filter :set_project_variable
8 | before_filter :check_required_permissions
9 | before_filter :check_xhr_request
10 | before_filter :find_repository_mirror, :except => [:index, :create]
11 |
12 | menu_item :settings, :only => :settings
13 |
14 | layout Proc.new { |controller| controller.request.xhr? ? 'popup' : 'base' }
15 |
16 | def index
17 | render_404
18 | end
19 |
20 | def create
21 | @mirror = RepositoryMirror.new(params[:repository_mirrors])
22 | if request.get?
23 | # display create view
24 | else
25 | @mirror.update_attributes(params[:repository_mirrors])
26 | @mirror.repository = @repository
27 |
28 | if @mirror.save
29 | flash[:notice] = l(:mirror_notice_created)
30 |
31 | redirect_url = success_url
32 | respond_to do |format|
33 | format.html {
34 | redirect_to redirect_url
35 | }
36 | format.js {
37 | render :update do |page|
38 | page.redirect_to redirect_url
39 | end
40 | }
41 | end
42 | else
43 | respond_to do |format|
44 | format.html {
45 | flash[:error] = l(:mirror_notice_create_failed)
46 | render :action => "create"
47 | }
48 | format.js {
49 | render :action => "form_error"
50 | }
51 | end
52 | end
53 | end
54 | end
55 |
56 | def edit
57 | end
58 |
59 | def update
60 | if @mirror.update_attributes(params[:repository_mirrors])
61 | flash[:notice] = l(:mirror_notice_updated)
62 |
63 | redirect_url = success_url
64 | respond_to do |format|
65 | format.html {
66 | redirect_to redirect_url
67 | }
68 | format.js {
69 | render :update do |page|
70 | page.redirect_to redirect_url
71 | end
72 | }
73 | end
74 | else
75 | respond_to do |format|
76 | format.html {
77 | flash[:error] = l(:mirror_notice_update_failed)
78 | render :action => "edit"
79 | }
80 | format.js {
81 | render :action => "form_error"
82 | }
83 | end
84 |
85 | end
86 | end
87 |
88 | def destroy
89 | if request.get?
90 | # display confirmation view
91 | else
92 | if params[:confirm]
93 | @mirror.destroy
94 |
95 | flash[:notice] = l(:mirror_notice_deleted)
96 | end
97 |
98 | redirect_url = success_url
99 | respond_to do |format|
100 | format.html {
101 | redirect_to(redirect_url)
102 | }
103 | end
104 | end
105 | end
106 |
107 | def settings
108 | end
109 |
110 | def push
111 | respond_to do |format|
112 | format.html {
113 | (@push_failed,@shellout) = @mirror.push
114 | }
115 | end
116 | end
117 |
118 | protected
119 |
120 | # This is a success URL to return to basic listing
121 | def success_url
122 | if GitHosting.multi_repos?
123 | url_for(:controller => 'repositories',
124 | :action => 'edit',
125 | :id => @repository.id)
126 | else
127 | url_for(:controller => 'projects',
128 | :action => 'settings',
129 | :id => @project.id,
130 | :tab => 'repository')
131 | end
132 | end
133 |
134 | def set_user_variable
135 | @user = User.current
136 | end
137 |
138 | def set_repository_variable
139 | @repository = Repository.find_by_id(params[:repository_id])
140 | if !@repository
141 | render_404
142 | end
143 | end
144 |
145 | def set_project_variable
146 | @project = @repository.project
147 | if !@project
148 | render_404
149 | end
150 | end
151 |
152 | def find_repository_mirror
153 | mirror = RepositoryMirror.find_by_id(params[:id])
154 |
155 | @mirrors = @repository.repository_mirrors
156 |
157 | if mirror and mirror.repository == @repository
158 | @mirror = mirror
159 | elsif mirror
160 | render_403
161 | else
162 | render_404
163 | end
164 | end
165 |
166 | def check_required_permissions
167 | # Deny access if the curreent user is not allowed to manage the project's repositoy
168 | if not @project.module_enabled?(:repository)
169 | render_403
170 | end
171 | not_enough_perms = true
172 | @user.roles_for_project(@project).each{|role|
173 | if role.allowed_to? :manage_repository
174 | not_enough_perms = false
175 | break
176 | end
177 | }
178 | if not_enough_perms
179 | render_403
180 | end
181 | end
182 |
183 | def check_xhr_request
184 | @is_xhr ||= request.xhr?
185 | end
186 |
187 | end
188 |
--------------------------------------------------------------------------------
/app/controllers/gitolite_public_keys_controller.rb:
--------------------------------------------------------------------------------
1 | class GitolitePublicKeysController < ApplicationController
2 | unloadable
3 |
4 | before_filter :require_login
5 | before_filter :set_user_variable
6 | before_filter :set_users_keys, :except => [:index, :new, :reset_rss_key]
7 | before_filter :find_gitolite_public_key, :except => [:index, :new, :reset_rss_key, :create]
8 |
9 | helper :issues
10 | helper :users
11 | helper :custom_fields
12 | helper :gitolite_public_keys
13 | include GitolitePublicKeysHelper
14 |
15 | def edit
16 | redirect_to url_for(:controller=>'my', :action=>'account', :public_key_id => @gitolite_public_key[:id])
17 | end
18 |
19 | def destroy
20 | GitHostingObserver.set_update_active(false)
21 | if !request.get?
22 | destroy_key
23 | end
24 | redirect_to @redirect_url
25 | GitHostingObserver.set_update_active(true)
26 | end
27 |
28 | def update
29 | GitHostingObserver.set_update_active(false)
30 | if !request.get?
31 | if params[:save_button]
32 | if @gitolite_public_key.update_attributes(params[:public_key])
33 | flash[:notice] = l(:notice_public_key_updated, :title=>keylabel(@gitolite_public_key))
34 |
35 | respond_to do |format|
36 | format.html { redirect_to @redirect_url }
37 | format.js { render :update do |page| page.redirect_to @redirect_url end }
38 | end
39 | else
40 | respond_to do |format|
41 | format.html {
42 | flash[:error] = l(:error_public_key_create_failed)
43 | # This doesn't give back validation errors (messy!)
44 | redirect_to @redirect_url
45 | }
46 | format.js {
47 | render :action => "form_error"
48 | }
49 | end
50 | end
51 | else
52 | destroy_key if params[:delete_button]
53 |
54 | respond_to do |format|
55 | format.html { redirect_to @redirect_url }
56 | format.js { render :update do |page| page.redirect_to @redirect_url end }
57 | end
58 | end
59 | end
60 | GitHostingObserver.set_update_active(true)
61 | end
62 |
63 | def create
64 | GitHostingObserver.set_update_active(false)
65 | @gitolite_public_key = GitolitePublicKey.new(params[:public_key].merge(:user => @user))
66 | if params[:create_button]
67 | if @gitolite_public_key.save
68 | flash[:notice] = l(:notice_public_key_added, :title=>keylabel(@gitolite_public_key))
69 |
70 | respond_to do |format|
71 | format.html { redirect_to @redirect_url }
72 | format.js { render :update do |page| page.redirect_to @redirect_url end }
73 | end
74 | else
75 | respond_to do |format|
76 | format.html {
77 | flash[:error] = l(:error_public_key_create_failed)
78 | # This doesn't give back validation errors (messy!)
79 | redirect_to @redirect_url
80 | }
81 | format.js {
82 | render :action => "form_error"
83 | }
84 | end
85 | end
86 | else
87 | respond_to do |format|
88 | format.html { redirect_to @redirect_url }
89 | format.js { render :update do |page| page.redirect_to @redirect_url end }
90 | end
91 | end
92 | GitHostingObserver.set_update_active(true)
93 | end
94 |
95 | protected
96 |
97 | def set_user_variable
98 | if params[:user_id]
99 | @user = (params[:user_id]=='current') ? User.current : User.find_by_id(params[:user_id])
100 | if @user
101 | @redirect_url = url_for(:controller => 'users', :action => 'edit', :id => params[:user_id], :tab => 'keys')
102 | else
103 | render_404
104 | end
105 | else
106 | @user = User.current
107 | @redirect_url = url_for(:controller => 'my', :action => 'account')
108 | end
109 | end
110 |
111 | def set_users_keys
112 | @gitolite_user_keys = @user.gitolite_public_keys.active.user_key.find(:all,:order => 'title ASC, created_at ASC')
113 | @gitolite_deploy_keys = @user.gitolite_public_keys.active.deploy_key.find(:all,:order => 'title ASC, created_at ASC')
114 | @gitolite_public_keys = @gitolite_user_keys + @gitolite_deploy_keys
115 | end
116 |
117 | def find_gitolite_public_key
118 | key = GitolitePublicKey.find_by_id(params[:id])
119 | if key and (@user == key.user || @user.admin?)
120 | @gitolite_public_key = key
121 | elsif key
122 | render_403
123 | else
124 | render_404
125 | end
126 | end
127 |
128 | def destroy_key
129 | @gitolite_public_key[:active] = 0
130 |
131 | # Since we are ultimately destroying this key, just force save (since old keys may fail new validations)
132 | @gitolite_public_key.save((Rails::VERSION::STRING.split('.')[0].to_i > 2) ? { :validate => false } : false)
133 |
134 | flash[:notice] = l(:notice_public_key_deleted, :title=>keylabel(@gitolite_public_key))
135 | end
136 | end
137 |
--------------------------------------------------------------------------------
/app/views/deployment_credentials/_view_list.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% if GitHostingHelper.can_create_deployment_keys(@repository.project) %>
4 |
5 | <%= link_to("Add Deployment Credential", url_for(:controller => 'deployment_credentials', :action => 'create_with_key', :repository_id => @repository.id), :class => 'icon icon-add add-deployment-credential' ) %>
6 |
7 | <% end %>
8 |
9 |
Deployment Credentials
10 |
11 | <% if @repository.deployment_credentials.active.any? %>
12 |
51 | <% else %>
52 |
53 | No Deployment Credentials Defined
54 |
55 | <% end %>
56 |
57 |
58 |
112 |
--------------------------------------------------------------------------------
/lib/git_hosting/patches/projects_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'principal'
2 | require_dependency 'user'
3 | require_dependency 'git_hosting'
4 | require_dependency 'projects_controller'
5 |
6 | module GitHosting
7 | module Patches
8 | module ProjectsControllerPatch
9 | def git_repo_init
10 | users = @project.member_principals.map(&:user).compact.uniq
11 | if users.length == 0
12 | membership = Member.new(
13 | :principal=>User.current,
14 | :project_id=>@project.id,
15 | :role_ids=>[3]
16 | )
17 | membership.save
18 | end
19 | if @project.module_enabled?('repository') && Setting.plugin_redmine_git_hosting['allProjectsUseGit'] == "true"
20 | # Create new repository
21 | repo = Repository.factory("Git")
22 | if GitHosting.multi_repos?
23 | @project.repositories << repo
24 | else
25 | @project.repository = repo
26 | end
27 | end
28 | end
29 |
30 | def disable_git_daemon_if_not_public
31 | # Go through all gitolite repos and diable git_daemon if necessary
32 | @project.gl_repos.each do |repo|
33 | if repo.extra.git_daemon == 1 && (not @project.is_public )
34 | repo.extra.git_daemon = 0;
35 | repo.extra.save
36 | repo.save # Trigger update_repositories
37 | end
38 | end
39 | end
40 |
41 | def create_with_disable_update
42 | # Turn of updates during repository update
43 | GitHostingObserver.set_update_active(false);
44 |
45 | # Do actual creation
46 | create_without_disable_update
47 |
48 | # Only create/fixup repo if project creation worked
49 | if validate_parent_id && @project.save
50 | # Fix up repository
51 | git_repo_init
52 |
53 | # Adjust daemon status
54 | disable_git_daemon_if_not_public
55 | end
56 |
57 | # Reenable updates to perform a single update
58 | GitHostingObserver.set_update_active(true);
59 | end
60 |
61 | def update_with_disable_update
62 | # Turn of updates during repository update
63 | GitHostingObserver.set_update_active(false);
64 |
65 | # Do actual update
66 | update_without_disable_update
67 |
68 | # Adjust daemon status
69 | disable_git_daemon_if_not_public
70 |
71 | if @project.gl_repos.detect {|repo| repo.url != GitHosting::repository_path(repo) || repo.url != repo.root_url}
72 | # Hm... something about parent hierarchy changed. Update us and our children
73 | GitHostingObserver.set_update_active(@project, :descendants)
74 | else
75 | # Reenable updates to perform a single update
76 | GitHostingObserver.set_update_active(true);
77 | end
78 | end
79 |
80 | def destroy_with_disable_update
81 | # Turn of updates during repository update
82 | GitHostingObserver.set_update_active(false);
83 |
84 | # Do actual update
85 | destroy_without_disable_update
86 |
87 | # Reenable updates to perform a single update
88 | GitHostingObserver.set_update_active(true);
89 | end
90 |
91 | def archive_with_disable_update
92 | # Turn of updates during repository update
93 | GitHostingObserver.set_update_active(false);
94 |
95 | # Do actual update
96 | archive_without_disable_update
97 |
98 | # Reenable updates to perform a single update
99 | GitHostingObserver.set_update_active(@project, :archive);
100 | end
101 |
102 | def unarchive_with_disable_update
103 | # Turn of updates during repository update
104 | GitHostingObserver.set_update_active(false);
105 |
106 | # Do actual update
107 | unarchive_without_disable_update
108 |
109 | # Reenable updates to perform a single update
110 | GitHostingObserver.set_update_active(@project);
111 | end
112 |
113 | def settings_with_disable_update
114 | # Turn of updates during repository update
115 | GitHostingObserver.set_update_active(false);
116 |
117 | # Do actual update
118 | settings_without_disable_update
119 |
120 | # Reenable updates to perform a single update
121 | if @project.module_enabled?(:repository)
122 | GitHostingObserver.set_update_active(@project);
123 | else
124 | GitHostingObserver.set_update_active(:archive);
125 | end
126 | end
127 |
128 | def self.included(base)
129 | base.class_eval do
130 | unloadable
131 | end
132 | base.send(:alias_method_chain, :create, :disable_update)
133 | base.send(:alias_method_chain, :update, :disable_update)
134 | base.send(:alias_method_chain, :destroy, :disable_update)
135 | base.send(:alias_method_chain, :archive, :disable_update)
136 | base.send(:alias_method_chain, :unarchive, :disable_update)
137 | base.send(:alias_method_chain, :settings, :disable_update)
138 | end
139 | end
140 | end
141 | end
142 |
143 | # Patch in changes
144 | ProjectsController.send(:include, GitHosting::Patches::ProjectsControllerPatch)
145 |
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | require 'redmine'
3 |
4 | require File.join(File.dirname(__FILE__), 'app', 'models', 'git_repository_extra')
5 | require File.join(File.dirname(__FILE__), 'app', 'models', 'git_cia_notification')
6 |
7 | Redmine::Plugin.register :redmine_git_hosting do
8 | name 'Redmine Git Hosting Plugin'
9 | author 'Eric Bishop, Pedro Algarvio, Christian Käser, Zsolt Parragi, Yunsang Choi, Joshua Hogendorn, Jan Schulz-Hofen, John Kubiatowicz and others'
10 | description 'Enables Redmine / ChiliProject to control hosting of git repositories'
11 | version '0.5.1x'
12 | url 'https://github.com/ericpaulbishop/redmine_git_hosting'
13 |
14 | settings :default => {
15 | 'httpServer' => 'localhost',
16 | 'httpServerSubdir' => '',
17 | 'gitServer' => 'localhost',
18 | 'gitUser' => 'git',
19 | 'gitConfigPath' => 'gitolite.conf', # Redmine gitolite config file
20 | 'gitConfigHasAdminKey' => 'true', # Conf file should have admin key
21 | 'gitRepositoryBasePath' => 'repositories/',
22 | 'gitRedmineSubdir' => '',
23 | 'gitRepositoryHierarchy' => 'true',
24 | 'gitRecycleBasePath' => 'recycle_bin/',
25 | 'gitRecycleExpireTime' => '24.0',
26 | 'gitLockWaitTime' => '10',
27 | 'gitoliteIdentityFile' => RAILS_ROOT + '/.ssh/gitolite_admin_id_rsa',
28 | 'gitoliteIdentityPublicKeyFile' => RAILS_ROOT + '/.ssh/gitolite_admin_id_rsa.pub',
29 | 'allProjectsUseGit' => 'false',
30 | 'gitDaemonDefault' => '1', # Default is Daemon enabled
31 | 'gitHttpDefault' => '1', # Default is HTTP_ONLY
32 | 'gitNotifyCIADefault' => '0', # Default is CIA Notification disabled
33 | 'deleteGitRepositories' => 'false',
34 | 'gitRepositoriesShowUrl' => 'true',
35 | 'gitCacheMaxTime' => '-1',
36 | 'gitCacheMaxElements' => '100',
37 | 'gitCacheMaxSize' => '16',
38 | 'gitHooksDebug' => 'false',
39 | 'gitHooksAreAsynchronous' => 'true',
40 | 'gitTempDataDir' => '/tmp/redmine_git_hosting/',
41 | 'gitScriptDir' => '',
42 | 'gitForceHooksUpdate' => 'true',
43 | 'gitRepositoryIdentUnique' => 'true'
44 | },
45 | :partial => 'redmine_git_hosting'
46 | project_module :repository do
47 | permission :create_repository_mirrors, :repository_mirrors => :create
48 | permission :view_repository_mirrors, :repository_mirrors => :index
49 | permission :edit_repository_mirrors, :repository_mirrors => :edit
50 | permission :create_repository_post_receive_urls, :repository_post_receive_urls => :create
51 | permission :view_repository_post_receive_urls, :repository_post_receive_urls => :index
52 | permission :edit_repository_post_receive_urls, :repository_post_receive_urls => :edit
53 | permission :create_deployment_keys, :deployment_credentials => :create_with_key
54 | permission :view_deployment_keys, :deployment_credentials => :index
55 | permission :edit_deployment_keys, :deployment_credentials => :edit
56 | end
57 | end
58 |
59 | # Set up autoload of patches
60 | require 'dispatcher' unless Rails::VERSION::MAJOR >= 3
61 | def git_hosting_patch(&block)
62 | if Rails::VERSION::MAJOR >= 3
63 | ActionDispatch::Calbacks.to_prepare(&block)
64 | else
65 | Dispatcher.to_prepare(:redmine_git_patches,&block)
66 | end
67 | end
68 | git_hosting_patch do
69 | patches=Dir[File.dirname(__FILE__)+"/lib/git_hosting/patches/*.rb"].map{|x| File.basename(x,".rb")}.sort
70 |
71 | # Special positioning necessary
72 | # Put git_adapter_patch last (make sure that git_cmd stays patched!)
73 | patches = (patches-["git_adapter_patch"]) << "git_adapter_patch"
74 | patches.each do |patch|
75 | require_dependency 'git_hosting/patches/'+File.basename(patch,".rb")
76 | end
77 | end
78 |
79 | # initialize hooks
80 | class GitProjectShowHook < Redmine::Hook::ViewListener
81 | render_on :view_projects_show_left, :partial => 'git_urls'
82 | end
83 |
84 | class GitRepoUrlHook < Redmine::Hook::ViewListener
85 | render_on :view_repositories_show_contextual, :partial => 'git_urls'
86 | end
87 |
88 | # Put Git SCM first in list of SCMs
89 | Redmine::Scm::Base.all.unshift("Git").uniq!
90 |
91 | # initialize observer
92 | # Don't initialize this while doing migration of primary system (i.e. Redmine/Chiliproject)
93 | migrating_primary = (File.basename($0) == "rake" && ARGV.include?("db:migrate"))
94 | config.after_initialize do
95 | if config.action_controller.perform_caching && !migrating_primary
96 | ActiveRecord::Base.observers = ActiveRecord::Base.observers << GitHostingObserver
97 | ActiveRecord::Base.observers = ActiveRecord::Base.observers << GitHostingSettingsObserver
98 |
99 | ActionController::Dispatcher.to_prepare(:git_hosting_observer_reload) do
100 | GitHostingObserver.instance.reload_this_observer
101 | end
102 | ActionController::Dispatcher.to_prepare(:git_hosting_settings_observer_reload) do
103 | GitHostingSettingsObserver.instance.reload_this_observer
104 | end
105 | end
106 | end
107 |
--------------------------------------------------------------------------------
/assets/stylesheets/git_url_display.css:
--------------------------------------------------------------------------------
1 |
2 | #git_url_box
3 | {
4 | height: 75px;
5 | padding: 10px 0 0;
6 | margin:0px;
7 | }
8 |
9 | #git_url_box ul li,
10 | .box #git_url_box ul li
11 | {
12 | list-style-image:none;
13 | padding:0px;
14 | margin:0px;
15 | }
16 |
17 | #git_url_box ul li:hover,
18 | .box #git_url_box ul li:hover
19 | {
20 | list-style-image:none;
21 | margin:0px;
22 | padding:0px;
23 | margin:0px;
24 | }
25 |
26 |
27 | #git_url_list
28 | {
29 | height: 23px;
30 | float: left;
31 | margin: 0px;
32 | padding: 0px 0px 0px 2px;
33 | list-style-image:none;
34 | }
35 |
36 | #git_url_list li
37 | {
38 | float: left;
39 | list-style-type: none;
40 | margin: 0px;
41 | padding: 0px;
42 | list-style-image:none;
43 | }
44 |
45 | #git_url_list li:hover
46 | {
47 | list-style-image:none;
48 | }
49 |
50 | #git_url_list li:first-child a
51 | {
52 | border-left-width: 1px;
53 |
54 | /* Standard, Opera 10, IE 9 */
55 | border-top-left-radius: 3px;
56 | border-bottom-left-radius: 3px;
57 | /* Konquerer */
58 | -khtml-border-top-left-radius: 3px;
59 | -khtml-border-bottom-left-radius: 3px;
60 | /* Gecko (Firefox, ...) */
61 | -moz-border-radius: 3px 0 0 3px;
62 | /* Webkit (Chrome, Safari, ...) */
63 | -webkit-border-top-left-radius: 3px;
64 | -webkit-border-bottom-left-radius: 3px;
65 | /* IE <= 9 not supported */
66 | }
67 |
68 | #git_url_list li a
69 | {
70 | background-color: #eee;
71 | background: url(../images/button.svg) 0 0 repeat; /* Opera needs an "image" :( - using svg for this so it will scale properly without looking too ugly */
72 | background: -khtml-gradient(linear, left top, left bottom, from(#f8f8f8), to(#ddd)); /* Konquerer */
73 | background: -moz-linear-gradient(top, #f8f8f8, #ddd); /* Gecko (Firefox, ...) */
74 | background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#ddd)); /* Webkit (Chrome, Safari, ...) */
75 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#dddddd'); /* IE 5.5 - 7 */
76 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#dddddd'); /* IE 8 */
77 |
78 | border-color: #bbb;
79 | border-style: solid;
80 | border-width: 1px 1px 1px 0;
81 |
82 | color: #333;
83 | display: block;
84 | font-size: 11px;
85 | font-weight: bold;
86 | line-height: 21px;
87 | margin: 0;
88 | padding: 0 10px 0 11px;
89 | text-decoration: none;
90 | text-shadow: 1px 1px 0 #fff;
91 | outline: none;
92 | }
93 |
94 | #git_url_list li a:hover,
95 | #git_url_list li a:focus
96 | {
97 | background-color: #507AAA;
98 | background: url(../images/button_focus.svg) 0 0 repeat; /* Opera needs an "image" :( - using svg for this so it will scale properly without looking too ugly */
99 | background: -khtml-gradient(linear, left top, left bottom, from(#759fcf), to(#507AAA)); /* Konquerer */
100 | background: -moz-linear-gradient(top, #759fcf, #507AAA); /* Gecko (Firefox, ...) */
101 | background: -webkit-gradient(linear, left top, left bottom, from(#759fcf), to(#507AAA)); /* Webkit (Chrome, Safari, ...) */
102 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#759fcf', endColorstr='#507AAA'); /* IE 5.5 - IE 7 */
103 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#759fcf', endColorstr='#507AAA'); /* IE 8 */
104 |
105 | color: #fff;
106 | text-shadow: -1px -1px 0 rgba(0,0,0,0.4);
107 | border-top-color: #759fcf;
108 | border-bottom-color: #507AAA;
109 | }
110 |
111 | #git_url_list li a.selected
112 | {
113 | background-color: #bbb;
114 | background: url(../images/button_selected.svg) 0 0 repeat; /* Opera needs an "image" :( - using svg for this so it will scale properly without looking too ugly */
115 | background: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#aaa)); /* Konquerer */
116 | background: -moz-linear-gradient(top, #ccc, #aaa); /* Gecko (Firefox, ...) */
117 | background: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#aaa)); /* Webkit (Chrome, Safari, ...) */
118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#aaaaaa'); /* IE 5.5 - IE 7 */
119 | -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#aaaaaa'); /* IE 8 */
120 |
121 | color: #000;
122 | text-shadow: 1px 1px 0 rgba(255,255,255,0.4);
123 | border-color: #bbb;
124 | }
125 |
126 | #git_url_text
127 | {
128 | border: 1px solid #bbb;
129 | border-width: 1px 1px 1px 1px;
130 | background-color: #fff;
131 | color: #000;
132 | font-size: 11px;
133 | height: 16px;
134 | padding: 3px 5px 2px;
135 | min-width:275px;
136 | width: 75%;
137 | font-family: Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",monospace;
138 | margin: 0;
139 | float: left;
140 | }
141 |
142 | #git_url_desc
143 | {
144 | color: #666;
145 | line-height: 23px;
146 | font-size: 11px;
147 | float: left;
148 | margin: 0 0 0 5px;
149 | }
150 |
151 | #git_url_access
152 | {
153 | font-weight: bold;
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/db/migrate/20120904060609_update_multi_repo_per_project.rb:
--------------------------------------------------------------------------------
1 | class UpdateMultiRepoPerProject < ActiveRecord::Migration
2 | def self.up
3 | if !columns("repository_mirrors").index{|x| x.name=="repository_id"}
4 | add_column :repository_mirrors, :repository_id, :integer
5 | begin
6 | say "Detaching repository mirrors from projects; attaching them to repositories..."
7 | RepositoryMirror.all.each do |mirror|
8 | mirror.repository_id = Project.find(mirror.project_id).repository.id
9 | mirror.save!
10 | end
11 | say "Success. Changed #{RepositoryMirror.all.count} records."
12 | rescue => e
13 | say "Failed to attach repository mirrors to repositories."
14 | say "Error: #{e.message}"
15 | end
16 | if columns("repository_mirrors").index{|x| x.name=="project_id"}
17 | remove_column :repository_mirrors, :project_id
18 | end
19 | end
20 |
21 | if !columns("repository_post_receive_urls").index{|x| x.name=="repository_id"}
22 | add_column :repository_post_receive_urls, :repository_id, :integer
23 | begin
24 | say "Detaching repository post-receive-urls from projects; attaching them to repositories..."
25 | RepositoryPostReceiveUrl.all.each do |prurl|
26 | prurl.repository_id = Project.find(prurl.project_id).repository.id
27 | prurl.save!
28 | end
29 | say "Success. Changed #{RepositoryPostReceiveUrl.all.count} records."
30 | rescue => e
31 | say "Failed to attach repositories post-receive-urls to repositories."
32 | say "Error: #{e.message}"
33 | end
34 | if columns("repository_post_receive_urls").index{|x| x.name=="project_id"}
35 | remove_column :repository_post_receive_urls, :project_id
36 | end
37 | end
38 |
39 | add_index :projects, [:identifier]
40 | if columns("repositories").index{|x| x.name=="identifier"}
41 | add_index :repositories, [:identifier]
42 | add_index :repositories, [:identifier, :project_id]
43 | end
44 | rename_column :git_caches, :proj_identifier, :repo_identifier
45 |
46 | begin
47 | # Add some new settings to settings page, if they don't exist
48 | valuehash = (Setting.plugin_redmine_git_hosting).clone
49 | if ((Repository.all.map(&:identifier).inject(Hash.new(0)) do |h,x|
50 | h[x]+=1 unless x.blank?
51 | h
52 | end.values.max) || 0) > 1
53 | # Oops -- have duplication. Force to false.
54 | valuehash['gitRepositoryIdentUnique'] = "false"
55 | else
56 | # If no duplication -- set to true only if it doesn't already exist
57 | valuehash['gitRepositoryIdentUnique'] ||= 'true'
58 | end
59 |
60 | if (Setting.plugin_redmine_git_hosting != valuehash)
61 | say "Added redmine_git_hosting settings: 'gitRepositoryIdentUnique' => #{valuehash['gitRepositoryIdentUnique']}"
62 | Setting.plugin_redmine_git_hosting = valuehash
63 | end
64 | rescue => e
65 | # ignore problems if plugin settings don't exist yet
66 | end
67 | end
68 |
69 | def self.down
70 | if !columns("repository_mirrors").index{|x| x.name=="project_id"}
71 | add_column :repository_mirrors, :project_id, :integer
72 | begin
73 | say "Detaching repository mirrors from repositories; re-attaching them to projects..."
74 | RepositoryMirror.all.each do |mirror|
75 | mirror.project_id = Repository.find(mirror.repository_id).project.id
76 | mirror.save!
77 | end
78 | say "Success. Changed #{RepositoryMirror.all.count} records."
79 | rescue => e
80 | say "Failed to re-attach repository mirrors to projects."
81 | say "Error: #{e.message}"
82 | end
83 | if columns("repository_mirrors").index{|x| x.name=="repository_id"}
84 | remove_column :repository_mirrors, :repository_id
85 | end
86 | end
87 |
88 | if !columns("repository_post_receive_urls").index{|x| x.name=="project_id"}
89 | add_column :repository_post_receive_urls, :project_id, :integer
90 | begin
91 | say "Detaching repository post-receive-urls from repositories; re-attaching them to projects..."
92 | RepositoryPostReceiveUrl.all.each do |prurl|
93 | prurl.project_id = Repository.find(prurl.repository_id).project.id
94 | prurl.save!
95 | end
96 | say "Success. Changed #{RepositoryPostReceiveUrl.all.count} records."
97 | rescue => e
98 | say "Failed to re-attach repository post-receive urls to projects."
99 | say "Error: #{e.message}"
100 | end
101 | if columns("repository_post_receive_urls").index{|x| x.name=="repository_id"}
102 | remove_column :repository_post_receive_urls, :repository_id
103 | end
104 | end
105 |
106 | remove_index :projects, [:identifier]
107 | if columns("repositories").index{|x| x.name=="identifier"}
108 | remove_index :repositories, [:identifier]
109 | remove_index :repositories, [:identifier, :project_id]
110 | end
111 | rename_column :git_caches, :repo_identifier, :proj_identifier
112 |
113 | begin
114 | # Remove above settings from plugin page
115 | valuehash = (Setting.plugin_redmine_git_hosting).clone
116 | valuehash.delete('gitRepositoryIdentUnique')
117 |
118 | if (Setting.plugin_redmine_git_hosting != valuehash)
119 | say "Removed redmine_git_hosting settings: 'gitRepositoryIdentUnique'"
120 | Setting.plugin_redmine_git_hosting = valuehash
121 | end
122 | rescue => e
123 | # ignore problems if table doesn't exist yet....
124 | end
125 | end
126 | end
127 |
--------------------------------------------------------------------------------
/lib/gitolite_recycle.rb:
--------------------------------------------------------------------------------
1 | module GitHosting
2 | # This class implements a basic recycle bit for repositories deleted from the gitolite repository
3 | #
4 | # Whenever repositories are deleted, we rename them and place them in the recycle_bin.
5 | # Assuming that GitoliteRecycle.delete_expired_files is called regularly, files in the recycle_bin
6 | # older than 'preserve_time' will be deleted. Both the path for the recycle_bin and the preserve_time
7 | # are settable as settings.
8 | #
9 | # John Kubiatowicz, 11/21/11
10 | class GitoliteRecycle
11 | TRASH_DIR_SEP = "__" # Separator character(s) used to replace '/' in name
12 |
13 | RECYCLE_BIN_IF_UNDEF = "recycle_bin/" # In case settings not migrated (normally from settings)
14 | PRESERVE_TIME_IF_UNDEF = 1440 # In case settings not migrated (normally from settings)
15 |
16 | def self.logger
17 | return GitHosting.logger
18 | end
19 |
20 | # Recycle bin base path (relative to git user home directory)
21 | def self.recycle_bin
22 | Setting.plugin_redmine_git_hosting['gitRecycleBasePath'] || RECYCLE_BIN_IF_UNDEF
23 | end
24 |
25 | # Recycle preservation time (in minutes)
26 | def self.preserve_time
27 | (Setting.plugin_redmine_git_hosting['gitRecycleExpireTime'].to_f * 60).to_i || PRESERVE_TIME_IF_UNDEF
28 | end
29 |
30 | # Scan through the recyclebin and delete files older than 'preserve_time' minutes
31 | def self.delete_expired_files
32 | return unless GitHosting.file_exists?(recycle_bin)
33 |
34 | result = %x[#{GitHosting.git_user_runner} find '#{recycle_bin}' -type d -regex '.*\.git' -cmin +#{preserve_time} -prune -print].chomp.split("\n")
35 | if result.length > 0
36 | logger.warn "Garbage-collecting expired file#{(result.length != 1) ? "s" : ""} from recycle bin:"
37 | result.each do |filename|
38 | begin
39 | GitHosting.shell %[#{GitHosting.git_user_runner} rm -r #{filename}]
40 | logger.warn " Deleting #{filename}"
41 | rescue
42 | logger.error "GitoliteRecycle.delete_expired_files() failed trying to delete repository #{filename}!"
43 | end
44 | end
45 |
46 | # Optionally remove recycle_bin (but only if empty). Ignore error if non-empty
47 | %x[#{GitHosting.git_user_runner} rmdir #{recycle_bin}]
48 | end
49 | end
50 |
51 | def self.move_repository_to_recycle repo_name
52 | # Only bother if actually exists!
53 | return unless GitHosting.git_repository_exists?(repo_name)
54 |
55 | repo_path = GitHosting.repository_path(repo_name)
56 | new_path = File.join(recycle_bin,"#{Time.now.to_i.to_s}#{TRASH_DIR_SEP}#{name_to_recycle_name(repo_name)}.git")
57 | begin
58 | GitHosting.shell %[#{GitHosting.git_user_runner} mkdir -p '#{recycle_bin}']
59 | GitHosting.shell %[#{GitHosting.git_user_runner} chmod 770 '#{recycle_bin}']
60 | GitHosting.shell %[#{GitHosting.git_user_runner} mv '#{repo_path}' '#{new_path}']
61 | logger.warn " Moving '#{repo_name}' from gitolite repository => '#{new_path}'. Will remain for at least #{preserve_time/60.0} hours"
62 | # If any empty directories left behind, try to delete them. Ignore failure.
63 | old_prefix = repo_name[/.*?(?=\/)/] # Top-level old directory without trailing '/'
64 | if old_prefix
65 | repo_subpath = File.join(GitHosting.repository_base, old_prefix)
66 | result = %x[#{GitHosting.git_user_runner} find '#{repo_subpath}' -depth -type d ! -regex '.*\.git/.*' -empty -delete -print].chomp.split("\n")
67 | result.each { |dir| logger.warn " Removing empty repository subdirectory: #{dir}"}
68 | end
69 | return true
70 | rescue
71 | logger.error "Attempt to move repository '#{repo_name}.git' to recycle bin failed"
72 | return false
73 | end
74 | end
75 |
76 | def self.recover_repository_if_present repo_name
77 | # Pull up any matching repositories. Sort them (beginning is representation of time)
78 | myregex = File.join(recycle_bin,"[0-9]+#{TRASH_DIR_SEP}#{name_to_recycle_name(repo_name)}.git")
79 | files = %x[#{GitHosting.git_user_runner} find '#{recycle_bin}' -type d -regex '#{myregex}' -prune].chomp.split("\n").sort {|x,y| y <=> x }
80 | if files.length > 0
81 | # Found something!
82 | logger.warn " Restoring '#{repo_name}.git' to gitolite repository from recycle bin (#{files.first})"
83 | begin
84 | prefix = repo_name[/.*(?=\/)/] # Complete directory path (if exists) without trailing '/'
85 | if prefix
86 | repo_prefix = File.join(GitHosting.repository_base, prefix)
87 | # Has subdirectory. Must reconstruct directory
88 | GitHosting.shell %[#{GitHosting.git_user_runner} mkdir -p '#{repo_prefix}']
89 | end
90 | repo_path = GitHosting.repository_path(repo_name)
91 | GitHosting.shell %[#{GitHosting.git_user_runner} mv '#{files.first}' '#{repo_path}']
92 |
93 | # Optionally remove recycle_bin (but only if empty). Ignore error if non-empty
94 | %x[#{GitHosting.git_user_runner} rmdir #{recycle_bin}]
95 | return true
96 | rescue
97 | logger.error "Attempt to recover '#{repo_name}.git' failed"
98 | return false
99 | end
100 | else
101 | false
102 | end
103 | end
104 |
105 | # This routine takes a name and turns it into a name for the recycle bit,
106 | # where we have a 1-level directory full of deleted repositories which
107 | # we keep for 'preserve_time'.
108 | def self.name_to_recycle_name repo_name
109 | new_trash_name = "#{repo_name}".gsub(/\//,"#{TRASH_DIR_SEP}")
110 | end
111 |
112 |
113 | end
114 | end
115 |
--------------------------------------------------------------------------------
/app/models/repository_mirror.rb:
--------------------------------------------------------------------------------
1 | class RepositoryMirror < ActiveRecord::Base
2 | STATUS_ACTIVE = 1
3 | STATUS_INACTIVE = 0
4 |
5 | PUSHMODE_MIRROR = 0
6 | PUSHMODE_FORCE = 1
7 | PUSHMODE_FAST_FORWARD = 2
8 |
9 | belongs_to :repository
10 |
11 | attr_accessible :url, :push_mode, :include_all_branches, :include_all_tags, :explicit_refspec, :active
12 |
13 | validates_uniqueness_of :url, :scope => [:repository_id]
14 | validates_presence_of :repository_id, :url
15 | validates_associated :repository
16 |
17 | validate :check_refspec
18 |
19 | before_validation :strip_whitespace
20 |
21 | named_scope :active, {:conditions => {:active => RepositoryMirror::STATUS_ACTIVE}}
22 | named_scope :inactive, {:conditions => {:active => RepositoryMirror::STATUS_INACTIVE}}
23 |
24 | named_scope :has_explicit_refspec, {:conditions => ['push_mode > 0']}
25 |
26 | def push
27 | repo_path = GitHosting.repository_path(repository)
28 |
29 | push_args = ""
30 | if push_mode == PUSHMODE_MIRROR
31 | push_args << "--mirror "
32 | else
33 | # Not mirroring -- other possible push_args
34 | push_args << "--force " if push_mode == PUSHMODE_FORCE
35 | push_args << "--all " if include_all_branches
36 | push_args << "--tags " if include_all_tags
37 | end
38 | push_args << "\"#{dequote(url)}\" "
39 | push_args << "\"#{dequote(explicit_refspec)}\" " unless explicit_refspec.blank?
40 |
41 | # mycom = %[ echo 'cd "#{repo_path}" ; env GIT_SSH=~/.ssh/run_gitolite_admin_ssh git push #{push_args}2>&1' | #{GitHosting.git_user_runner} "bash" ]
42 | # GitHosting.logger.error "Pushing: #{mycom}"
43 | shellout = %x[ echo 'cd "#{repo_path}" ; env GIT_SSH=~/.ssh/run_gitolite_admin_ssh git push #{push_args}2>&1' | #{GitHosting.git_user_runner} "bash" ].chomp
44 | push_failed = ($?.to_i!=0) ? true : false
45 | if (push_failed)
46 | GitHosting.logger.error "[ Pushing changes to mirror: #{url} ... Failed!"
47 | GitHosting.logger.error " "+shellout.split("\n").join("\n ")+" ]"
48 | else
49 | GitHosting.logger.info "[ Pushing changes to mirror: #{url} ... Succeeded! ]"
50 | end
51 | [push_failed,shellout]
52 | end
53 |
54 | # If we have an explicit refspec, check it against incoming payloads
55 | # Special case: if we do not pass in any payloads, return true
56 | def needs_push(payloads=[])
57 | return true if payloads.empty?
58 | return true if push_mode==PUSHMODE_MIRROR
59 |
60 | refspec_parse = explicit_refspec.match(/^\+?([^:]*)(:[^:]*)?$/)
61 | payloads.each do |payload|
62 | if splitpath = refcomp_parse(payload[:ref])
63 | return true if payload[:ref] == refspec_parse[1] # Explicit Reference Spec complete path
64 | return true if splitpath[:name] == refspec_parse[1] # Explicit Reference Spec no type
65 | return true if include_all_branches && splitpath[:type] == "heads"
66 | return true if include_all_tags && splitpath[:type] == "tags"
67 | end
68 | end
69 | false
70 | end
71 |
72 | def to_s
73 | return File.join("#{repository.project.identifier}-#{url}")
74 | end
75 |
76 | protected
77 |
78 | # Strip leading and trailing whitespace
79 | def strip_whitespace
80 | self.url = url.strip
81 | self.explicit_refspec = explicit_refspec.strip
82 | end
83 |
84 | # Put backquote in front of crucial characters
85 | def dequote(in_string)
86 | in_string.gsub(/[$,"\\\n]/) {|x| "\\"+x}
87 | end
88 |
89 | def check_refspec
90 | self.explicit_refspec = explicit_refspec.strip
91 |
92 | if push_mode == PUSHMODE_MIRROR
93 | # clear out all extra parameters.. (we use javascript to hide them anyway)
94 | self.include_all_branches = false
95 | self.include_all_tags = false
96 | self.explicit_refspec = ""
97 | elsif include_all_branches && include_all_tags
98 | errors.add_to_base("Cannot #{l(:field_include_all_branches)} and #{l(:field_include_all_tags)} at the same time.")
99 | errors.add(:explicit_refspec, "cannot be used with #{l(:field_include_all_branches)} or #{l(:field_include_all_tags)}") unless explicit_refspec.blank?
100 | elsif !explicit_refspec.blank?
101 | errors.add(:explicit_refspec, "cannot be used with #{l(:field_include_all_branches)}.") if include_all_branches
102 |
103 | # Check format of refspec
104 | if !(refspec_parse = explicit_refspec.match(/^\+?([^:]*)(:([^:]*))?$/)) || !refcomp_valid(refspec_parse[1]) || !refcomp_valid(refspec_parse[3])
105 | errors.add(:explicit_refspec, "is badly formatted.")
106 | elsif !refspec_parse[1] || refspec_parse[1]==""
107 | errors.add(:explicit_refspec, "cannot have null first component (will delete remote branch(s))")
108 | end
109 | elsif !include_all_branches && !include_all_tags
110 | errors.add_to_base("Must include at least one item to push.")
111 | end
112 | end
113 |
114 | def refcomp_valid(spec)
115 | # Allow null or empty components
116 | if !spec || spec=="" || refcomp_parse(spec)
117 | true
118 | else
119 | false
120 | end
121 | end
122 |
123 | # Parse a reference component. Three possibilities:
124 | #
125 | # 1) refs/type/name
126 | # 2) name
127 | #
128 | # here, name can have many components.
129 | @@refcomp = "[\\.\\-\\w_\\*]+"
130 | def refcomp_parse(spec)
131 | if (refcomp_parse = spec.match(/^(refs\/)?((#{@@refcomp})\/)?(#{@@refcomp}(\/#{@@refcomp})*)$/))
132 | if refcomp_parse[1]
133 | # Should be first class. If no type component, return fail
134 | if refcomp_parse[3]
135 | {:type=>refcomp_parse[3], :name=>refcomp_parse[4]}
136 | else
137 | nil
138 | end
139 | elsif refcomp_parse[3]
140 | {:type=>nil, :name=>(refcomp_parse[3]+"/"+refcomp_parse[4])}
141 | else
142 | {:type=>nil, :name=>refcomp_parse[4]}
143 | end
144 | else
145 | nil
146 | end
147 | end
148 |
149 | end
150 |
--------------------------------------------------------------------------------
/app/views/gitolite_public_keys/_view.html.erb:
--------------------------------------------------------------------------------
1 | <%= stylesheet_link_tag('application', :plugin => 'redmine_git_hosting')%>
2 |
3 | <%=l(:label_public_keys)%>
4 |
5 | <% if !@gitolite_user_keys.empty? || @gitolite_deploy_keys.empty? %>
6 | <%= @gitolite_deploy_keys.empty? ? l(:label_current_public_keys) : l(:label_current_user_keys) %>
7 |
8 | <% if @gitolite_user_keys.empty? %>
9 | <%=l(:label_no_public_keys)%>
10 | <%end %>
11 | <% @gitolite_user_keys.each do |key| %>
12 |
13 | <%= h(key) %>
14 | <% if params[:id] %>
15 | <%= "keydir/#{key.identifier}.pub" %>
16 | <% end %>
17 |
18 | <%= link_to(l(:button_edit), { :public_key_id => key.id, :tab => params[:id]&&'keys'}, :class => 'icon icon-edit') %>
19 | <%= link_to(l(:button_delete), public_key_path(key, :user_id=>params[:id]), :method => 'delete', :class => 'icon icon-del', :confirm=>l(:text_gitolite_key_destroy_confirmation, :title=>keylabel(key))) %>
20 |
21 |
22 | <% end %>
23 |
24 |
25 | <% end %>
26 |
27 | <% if !@gitolite_deploy_keys.empty? %>
28 | <%= l(:label_current_deploy_keys)%>
29 |
30 | <% if @gitolite_deploy_keys.empty? %>
31 | <%=l(:label_no_public_keys)%>
32 | <%end %>
33 | <% @gitolite_deploy_keys.each do |key| %>
34 |
35 | <%= h(key) %>
36 | <% if params[:id] %>
37 | <%= "keydir/#{key.identifier}.pub" %>
38 | <% end %>
39 |
40 | <%= link_to(l(:button_edit), { :public_key_id => key.id, :tab => params[:id]&&'keys'}, :class => 'icon icon-edit') %>
41 | <%= link_to(l(:button_delete), public_key_path(key, :user_id=>params[:id]), :method => 'delete', :class => 'icon icon-del', :confirm=>l(:text_gitolite_key_destroy_confirmation, :title=>keylabel(key))) %>
42 |
43 |
44 | <% end %>
45 |
46 |
47 | <% end %>
48 |
49 | <% @new_key = @gitolite_public_key.new_record? %>
50 | <%= @new_key ? l(:label_public_key_new) : l(:label_public_key_edit) %>
51 | <%= error_messages_for 'gitolite_public_key' %>
52 | <% labelled_remote_form_for :public_key, @gitolite_public_key,
53 | :url=>{:controller=>'gitolite_public_keys', :action=>@new_key ? 'create' : 'update', :id=>@gitolite_public_key.id, :user_id=>params[:id], :tab => params[:id]&&'keys'},
54 | :html => {:method=>(@new_key ? :post : :put)} do |f| %>
55 | <%= f.text_field :title, :label => :label_identifier_can_be_arbitrary, :required => true, :style => 'width:99%;' %>
56 | <% if @gitolite_public_key.key_type==1 || GitHostingHelper.can_create_deployment_keys_for_some_project(@user) %>
57 |
58 |
59 | <%= f.select :key_type, options_for_select([[l(:label_user_key),0],[l(:label_deploy_key),1]], :selected => @gitolite_public_key.key_type, :disabled => (@new_key ? [] : [0,1])), :required => true, :label => :field_key_type %>
60 |
61 |
62 |
63 | <%= f.check_box :delete_when_unused, :required => true, :label => :field_delete_when_unused %>
64 |
65 |
66 |
67 | <% end %>
68 | <%= f.text_area :key, :label => (@new_key? :label_cut_and_paste : :field_public_key), :required => true, :disabled => !@new_key,
69 | :style => "width:99%;height:200px;overflow:auto;",
70 | :cols => nil, :rows => nil %>
71 | <%= hidden_field_tag :button_submit_field, "true" %>
72 | <% if !@new_key%>
73 | <%= l(:label_key_cannot_be_changed_please_create_new_key) %>
74 | <%= submit_tag l(:button_save), :name=>'save_button' %>
75 | <%= submit_tag l(:button_delete), :name=>'delete_button', :confirm => l(:text_gitolite_key_destroy_confirmation,:title=>(@gitolite_public_key[:title].blank? ? l(:text_this_key) : keylabel(@gitolite_public_key))) %>
76 | <%= submit_tag l(:button_cancel), :name=>'cancel_button' %>
77 | <% else %>
78 |
79 | <%= submit_tag l(:button_create), :name=>'create_button' %>
80 | <% mystyle = (@gitolite_public_key.errors.any? ? '' : 'style="display:none;"') %>
81 | >
82 | <%= submit_tag l(:button_cancel), :name=>'cancel_button' %>
83 |
84 | <% end %>
85 | <% end %>
86 |
87 |
88 |
89 |
123 |
--------------------------------------------------------------------------------
/app/views/repository_mirrors/_view_list.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% if GitHostingHelper.can_create_mirrors(@repository.project) %>
4 |
5 | <%= link_to("Add Repository Mirror", url_for(:controller => 'repository_mirrors', :action => 'create', :repository_id => @repository.id), :class => 'icon icon-add add-mirror' ) %>
6 |
7 | <% end %>
8 |
9 |
Repository Mirrors
10 |
11 | <% if @repository.repository_mirrors.any? %>
12 |
44 | <% else %>
45 |
46 | No Mirrors Defined
47 |
48 | <% end %>
49 |
50 | <% mirror_pubkey = GitHosting.mirror_push_public_key %>
51 |
52 |
53 |
<%= image_tag 'paste.png', :plugin => 'redmine_git_hosting' %>
54 |
55 |
Mirrors Must Grant Write Access To The Following Public Key:
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | <% content_for :header_tags do %>
64 | <%= stylesheet_link_tag('zero_clipboard', :plugin => 'redmine_git_hosting') %>
65 | <%= javascript_include_tag('ZeroClipboard', :plugin => 'redmine_git_hosting') %>
66 | <%= javascript_include_tag('zero_clipboard_setup', :plugin => 'redmine_git_hosting') %>
67 | <% end %>
68 |
69 |
159 |
--------------------------------------------------------------------------------