--- /dev/null
+= le\r
+\r
+Description goes here\r
--- /dev/null
+class LdapUsersController < ApplicationController\r
+ unloadable\r
+ before_filter :require_admin, :setup_auth_source\r
+\r
+ def index\r
+ @ldap_users = LdapUser.find(:all)\r
+ end\r
+\r
+ def new\r
+ @ldap_user = LdapUser.new\r
+ render :action => "edit"\r
+ end\r
+\r
+ def create\r
+ @user = User.new(:language => Setting.default_language)\r
+ @ldap_user = LdapUser.new\r
+ @user.login = @ldap_user.login = params[:ldap_user][:login]\r
+\r
+ if assign_params_and_save\r
+ flash[:notice] = l(:notice_successful_create)\r
+\r
+ if @user.save_without_validation\r
+ @user.auth_source = nil # dummy\r
+ Mailer.deliver_account_information(@user, @ldap_user.password) if params[:send_information]\r
+ else\r
+ flash[:error] = l(:error_failed_to_create_redmine_user)\r
+ end\r
+\r
+ redirect_to :action => 'edit', :id => @ldap_user.login\r
+ else\r
+ render :action => 'edit'\r
+ end\r
+ end\r
+\r
+ def edit\r
+ @ldap_user = LdapUser.find(params[:id])\r
+ end\r
+\r
+ def update\r
+ @user = User.find_by_login(params[:id]) || User.new(:login => params[:id])\r
+ @ldap_user = LdapUser.find(params[:id])\r
+\r
+ if assign_params_and_save\r
+ flash[:notice] = l(:notice_successful_update)\r
+ if @ldap_user.admin? && !params[:ldap_user][:password].blank?\r
+ flash[:warning] = l(:warning_need_to_restart)\r
+ end\r
+ \r
+ if @user.save_without_validation\r
+ @user.auth_source = nil # dummy\r
+ Mailer.deliver_account_information(@user, @ldap_user.password) if params[:send_information] && !@ldap_user.password.blank?\r
+ else\r
+ flash[:error] = l(:error_failed_to_update_redmine_user)\r
+ end\r
+\r
+ redirect_to :action => 'edit', :id => @ldap_user.login\r
+ else\r
+ render :action => 'edit'\r
+ end\r
+ end\r
+\r
+ def destroy\r
+ #@ldap_user = LdapUser.find(params[:id])\r
+ end\r
+\r
+ private\r
+ def setup_auth_source\r
+ setting = RedmineLeSetting.instance\r
+ return render_403 if setting.use_external_ldap\r
+ return render_404 unless @auth_source = LdapUser.auth_source = setting.auth_source\r
+ end\r
+\r
+ def assign_params_and_save\r
+ h = params[:ldap_user]\r
+ attrs = %w[firstname lastname mail]\r
+ attrs.each {|attr|\r
+ @user.send(attr+"=", @ldap_user.send(attr+"=", h[attr]))\r
+ }\r
+ @ldap_user.password = h[:password]\r
+ @ldap_user.password_confirmation = h[:password_confirmation]\r
+\r
+ unless @user.valid?\r
+ @user.errors.each_error {|attr, error|\r
+ if attrs.include?(attr) && @user.send(attr+"_changed?")\r
+ @ldap_user.errors.add_to_base(error.full_message)\r
+ end\r
+ }\r
+ end\r
+ @user.auth_source ||= @auth_source\r
+\r
+ RedmineLeSetting.transaction do\r
+ @ldap_user.errors.empty? && @ldap_user.save\r
+ end\r
+\r
+ @ldap_user.errors.empty?\r
+ end\r
+end\r
--- /dev/null
+class RedmineLeSettingsController < ApplicationController\r
+ unloadable\r
+ before_filter :require_admin\r
+\r
+ def index\r
+ @setting = RedmineLeSetting.instance\r
+ end\r
+\r
+ def update\r
+ @setting = RedmineLeSetting.instance\r
+ @setting.update_attributes(params[:redmine_le_setting])\r
+ if @setting.save\r
+ flash[:notice] = l(:notice_successful_update)\r
+ flash[:warning] = l(:warning_need_to_restart)\r
+ redirect_to :action => 'index'\r
+ else\r
+ render :action => 'index'\r
+ end\r
+ end\r
+end\r
--- /dev/null
+class HookConfig\r
+ def initialize(project)\r
+ @project = project\r
+ end\r
+\r
+ def filename\r
+ @filename = @project.repository_path + "/hooks/hook_config.yml"\r
+ end\r
+\r
+ def config\r
+ @config ||= (exists? ? YAML.load_file(filename) : {\r
+ "pre_commit" => nil,\r
+ "post_commit" => {\r
+ "fetch_changesets" => nil,\r
+ "perform_build" => {"jobs" => []}\r
+ }\r
+ })\r
+ end\r
+\r
+ def save\r
+ File.open(filename, "w") {|f|\r
+ f.print(config.to_yaml)\r
+ }\r
+ end\r
+\r
+ def exists?\r
+ File.file?(filename)\r
+ end\r
+\r
+ def [](key)\r
+ config[key]\r
+ end\r
+end\r
--- /dev/null
+require 'active_ldap'\r
+\r
+class LdapUser < ActiveLdap::Base\r
+ unloadable\r
+ ldap_mapping :prefix => "", :dn_attribute => "uid",\r
+ :classes => %w[person inetOrgPerson organizationalPerson top]\r
+\r
+ validates_confirmation_of :password, :allow_nil => true\r
+\r
+ attr_accessor :password, :password_confirmation\r
+\r
+ def self.auth_source\r
+ @auth_source\r
+ end\r
+\r
+ def self.auth_source=(source)\r
+ setup_connection(\r
+ :host => source.host,\r
+ :port => source.port,\r
+ :base => source.base_dn,\r
+ :bind_dn => source.account,\r
+ :password => source.account_password\r
+ )\r
+\r
+ @auth_source = source\r
+ end\r
+\r
+ def admin?\r
+ login == RedmineLeSetting.admin_account\r
+ end\r
+\r
+ def auth_source\r
+ self.class.auth_source\r
+ end\r
+ \r
+ def login\r
+ self[self.auth_source.attr_login]\r
+ end\r
+\r
+ def login=(value)\r
+ self[auth_source.attr_login] = value\r
+ end\r
+\r
+ def firstname\r
+ self[auth_source.attr_firstname]\r
+ end\r
+\r
+ def firstname=(value)\r
+ self[auth_source.attr_firstname] = value\r
+ end\r
+\r
+ def lastname\r
+ self[auth_source.attr_lastname]\r
+ end\r
+\r
+ def lastname=(value)\r
+ self[:cn] ||= value\r
+ self[auth_source.attr_lastname] = value\r
+ end\r
+\r
+ def mail\r
+ self[auth_source.attr_mail]\r
+ end\r
+\r
+ def mail=(value)\r
+ self[auth_source.attr_mail] = value\r
+ end\r
+\r
+ protected\r
+ def validate\r
+ if !password.blank? && password.size < l=Setting.password_min_length.to_i\r
+ add_error_message(:password, :too_short, :count => l)\r
+ end\r
+\r
+ if mail.blank?\r
+ add_error_message(:mail, :blank)\r
+ elsif mail !~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/\r
+ add_error_message(:mail, :invalid)\r
+ end\r
+ end\r
+\r
+ def validate_on_create\r
+ add_error_message(:password, :blank) if password.blank?\r
+ add_error_message(:login, :taken) if User.find_by_login(login)\r
+ end\r
+\r
+ def before_save\r
+ unless password.blank?\r
+ self[:userPassword] = password\r
+ if admin?\r
+ setting = RedmineLeSetting.instance\r
+ setting.admin_password = password\r
+ setting.save\r
+ end\r
+ end\r
+ end\r
+\r
+ private\r
+ def add_error_message(attr, msg, options = {})\r
+ @dummy_user ||= User.new\r
+ self.errors.add_to_base(ActiveRecord::Error.new(@dummy_user, attr, msg, options).full_message)\r
+ end\r
+end\r
--- /dev/null
+class RedmineLeSetting < ActiveRecord::Base\r
+ unloadable\r
+\r
+ @@skip_callbacks = false\r
+ EMAIL_YAML = RAILS_ROOT + "/config/email.yml"\r
+\r
+ belongs_to :auth_source\r
+\r
+ validates_presence_of :auth_source_id, :admin_account, :admin_password\r
+ \r
+ def self.instance\r
+ @instance ||= (first || new)\r
+ end\r
+\r
+ def self.[](name)\r
+ instance[name]\r
+ end\r
+\r
+ def self.[]=(name, value)\r
+ instance[name] = value\r
+ end\r
+\r
+ def self.method_missing(name, *args)\r
+ instance.send(name, *args)\r
+ end\r
+\r
+ def self.transaction(&block)\r
+ @xml_changes = {}\r
+ @text_changes = {}\r
+ @file_changes = {}\r
+ @error_list = {}\r
+ super(&block)\r
+ rescue => err\r
+ @xml_changes.dup.each {|filename, xpath_values|\r
+ replace_xml(filename, *xpath_values)\r
+ }\r
+ @xml_changes = {}\r
+ @text_changes.dup.each {|filename, regexp_values|\r
+ replace_text(filename, *regexp_values)\r
+ }\r
+ @text_changes = {}\r
+ @file_changes.each {|filename, content|\r
+ File.open(filename, "w") {|f| f.write(content)}\r
+ }\r
+ @file_changes = {}\r
+ raise err\r
+ end\r
+\r
+ def self.skip_callbacks(&block)\r
+ @@skip_callbacks = true\r
+ result = yield\r
+ @@skip_callbacks = false\r
+ result\r
+ end\r
+\r
+ def search_ldap_user(username = nil)\r
+ username ||= admin_account\r
+ source = LdapUser.auth_source = RedmineLeSetting.auth_source\r
+ LdapUser.find(:filter => [source.attr_login, username])\r
+ end\r
+\r
+ def search_dn(username = nil)\r
+ user = search_ldap_user(username)\r
+ user && user.dn.to_s\r
+ end\r
+\r
+ def base64_admin_password\r
+ admin_password && Base64.encode64(admin_password).chomp\r
+ end\r
+\r
+ def smtp_settings\r
+ @email_config ||= File.file?(EMAIL_YAML) ? YAML.load_file(EMAIL_YAML) : {}\r
+ conf = @email_config[RAILS_ENV] ||= {}\r
+ conf["delivery_method"] ||= :smtp\r
+ conf["smtp_settings"] ||= {}\r
+ end\r
+\r
+ def smtp_settings_changed?\r
+ !!@smtp_settings_changed\r
+ end\r
+\r
+ def smtp_server\r
+ smtp_settings["address"]\r
+ end\r
+\r
+ def smtp_server=(value)\r
+ set_smtp_setting("address", value)\r
+ end\r
+\r
+ def smtp_port\r
+ smtp_settings["port"] ||= 25\r
+ end\r
+\r
+ def smtp_port=(value)\r
+ set_smtp_setting("port", value.to_i)\r
+ end\r
+\r
+ def smtp_user\r
+ smtp_settings["user_name"]\r
+ end\r
+\r
+ def smtp_user=(value)\r
+ set_smtp_setting("user_name", value)\r
+ end\r
+\r
+ def smtp_password\r
+ smtp_settings["password"]\r
+ end\r
+\r
+ def smtp_password=(value)\r
+ set_smtp_setting("password", value)\r
+ end\r
+\r
+ def smtp_sender\r
+ Setting.mail_from\r
+ end\r
+\r
+ def smtp_sender=(value)\r
+ @smtp_settings_changed = true if smtp_sender != value\r
+ @smtp_sender = value\r
+ end\r
+\r
+ protected\r
+ def validate_on_update\r
+ return unless use_external_ldap\r
+ return unless admin_account_changed? || admin_password_changed?\r
+ user = search_ldap_user\r
+ valid = user && begin\r
+ user.bind(admin_password)\r
+ rescue ActiveLdap::AuthenticationError, ActiveLdap::LdapError::UnwillingToPerform\r
+ false\r
+ end\r
+ errors.add_to_base(l(:notice_account_invalid_creditentials)) unless valid\r
+ end\r
+\r
+ def before_save\r
+ return if @@skip_callbacks\r
+ change_smtp_settings if smtp_settings_changed?\r
+ change_admin_account if admin_account_changed? || admin_password_changed?\r
+ end\r
+\r
+ private\r
+ def change_smtp_settings\r
+ if @smtp_sender && @smtp_sender != smtp_sender\r
+ Setting.mail_from = @smtp_sender\r
+ end\r
+\r
+ smtp_settings["domain"] ||= "localhost"\r
+ if smtp_user.blank? || smtp_password.blank?\r
+ %w[authentication user_name password].each {|key|\r
+ smtp_settings.delete(key)\r
+ }\r
+ else\r
+ smtp_settings["authentication"] = :login\r
+ end\r
+\r
+ self.class.replace_xml(\r
+ RedmineLe::HOME + "/hudson/home/hudson.tasks.Mailer.xml",\r
+ ["//smtpHost", smtp_server],\r
+ ["//adminAddress", smtp_sender],\r
+ ["//smtpAuthUsername", smtp_user],\r
+ ["//smtpAuthPassword", smtp_password]\r
+ )\r
+ self.class.write_file(EMAIL_YAML, YAML.dump(@email_config))\r
+ @smtp_settings_changed = nil\r
+ end\r
+\r
+ def change_admin_account\r
+ dn = use_external_ldap ? search_dn : auth_source.account\r
+\r
+ Repository::Subversion.all(:conditions => [\r
+ "url LIKE ? AND login = ?", 'http%://localhost%/svn/%', admin_account_was\r
+ ]).each {|repos|\r
+ repos.login = admin_account\r
+ repos.password = admin_password\r
+ repos.save!\r
+ }\r
+\r
+ auth_source.account = dn\r
+ auth_source.account_password = admin_password\r
+ auth_source.save!\r
+\r
+ base = "//credentials/entry/string[contains(., '//localhost:#{RedmineLe::HTTP_PORT}')]/.."\r
+ self.class.replace_xml(\r
+ RedmineLe::HOME + "/hudson/home/hudson.scm.SubversionSCM.xml",\r
+ [base + "//userName", admin_account],\r
+ [base + "//password", base64_admin_password]\r
+ )\r
+\r
+ self.class.replace_xml(\r
+ RedmineLe::HOME + "/hudson/home/config.xml",\r
+ ["//securityRealm/managerDN", dn],\r
+ ["//securityRealm/managerPassword", base64_admin_password]\r
+ )\r
+\r
+ self.class.replace_text(\r
+ RedmineLe::HOME + "/apache/conf/conf.d/subversion.conf",\r
+ [/AuthLDAPBindDN\s+(.*)$/, dn],\r
+ [/AuthLDAPBindPassword\s+(.*)$/, admin_password]\r
+ )\r
+ end\r
+\r
+ def self.replace_xml(filename, *xpath_values)\r
+ doc = REXML::Document.new(File.new(filename))\r
+\r
+ xpath_values.each {|xpath, value|\r
+ unless elem = doc.elements[xpath]\r
+ (@error_list[filename] ||= []) << xpath if @error_list\r
+ next\r
+ end\r
+ oldvalue = elem.text\r
+ elem.text = value\r
+ (@xml_changes[filename] ||= []) << [xpath, oldvalue] if @xml_changes\r
+ }\r
+\r
+ File.open(filename, "w") {|f| doc.write(f)}\r
+ end\r
+\r
+ def self.replace_text(filename, *regexp_values)\r
+ content = File.read(filename)\r
+\r
+ regexp_values.each {|regexp, value|\r
+ begin\r
+ content[regexp, 1] = value\r
+ (@text_changes[filename] ||= []) << [regexp, $1] if @text_changes\r
+ rescue IndexError\r
+ (@error_list[filename] ||= []) << regexp.inspect if @error_list\r
+ end\r
+ }\r
+\r
+ File.open(filename, "w") {|f| f.write(content)}\r
+ end\r
+\r
+ def self.write_file(filename, content)\r
+ if @file_changes\r
+ @file_changes[filename] = File.file?(filename) ? File.read(filename) : ""\r
+ end\r
+ File.open(filename, "w") {|f| f.write(content)}\r
+ end\r
+\r
+ def set_smtp_setting(key, value)\r
+ v = "@smtp_#{key}_was"\r
+ v = instance_variable_get(v) || instance_variable_set(v, smtp_settings[key])\r
+ @smtp_settings_changed = true if v != value\r
+ smtp_settings[key] = value\r
+ end\r
+end\r
--- /dev/null
+<h2><%= link_to l(:label_ldap_user_plural), :action => 'index' %> » <%= @ldap_user.new_record? ? l(:label_user_new) : h(@ldap_user.login) %></h2>\r
+\r
+<%\r
+ args = {:url => {:action => @ldap_user.new_record? ? "create" : "update"}}\r
+ args[:html] = {:method => :put} unless @ldap_user.new_record?\r
+%>\r
+<% labelled_tabular_form_for :ldap_user, @ldap_user, args do |f| %>\r
+<%= f.error_messages %>\r
+<div class="box">\r
+<% if @ldap_user.new_record? %>\r
+ <p><%= f.text_field :login, :required => true, :size => 25 %></p>\r
+<% end %>\r
+ <p><%= f.password_field :password, :required => true, :size => 25 %></p>\r
+ <p><%= f.password_field :password_confirmation, :required => true, :size => 25 %></p>\r
+ <p><%= f.text_field :firstname, :required => true %></p>\r
+ <p><%= f.text_field :lastname, :required => true %></p>\r
+ <p><%= f.text_field :mail, :required => true %></p>\r
+</div>\r
+<%= f.submit l(@ldap_user.new_record? ? :button_create : :button_save) %>\r
+<%= check_box_tag 'send_information', 1, true %> <%= l(:label_send_information) %>\r
+<% end %>\r
--- /dev/null
+<% html_title(l(:label_ldap_user_plural)) %>\r
+\r
+<div class="contextual">\r
+<%= link_to l(:label_user_new), {:action => 'new'}, :class => 'icon icon-add' %>\r
+</div>\r
+\r
+<h2><%= l(:label_ldap_user_plural) %></h2>\r
+\r
+<table class="list"> \r
+ <thead>\r
+ <tr>\r
+ <th><%= l(:field_login) %></th>\r
+ <th><%= l(:field_firstname) %></th>\r
+ <th><%= l(:field_lastname) %></th>\r
+ <th><%= l(:field_mail) %></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ <% @ldap_users.each do |user| %>\r
+ <tr class="<%= cycle("odd", "even") %>">\r
+ <td><%= link_to(h(user.login), :action => 'edit', :id => user.login) %></td>\r
+ <td><%= h(user.firstname) %></td>\r
+ <td><%= h(user.lastname) %></td>\r
+ <td><%= h(user.mail) %></td>\r
+ </tr>\r
+ <% end %>\r
+ </tbody>\r
+</table>\r
--- /dev/null
+<h2>RedmineLE</h2>\r
+\r
+<% unless RedmineLeSetting.use_external_ldap %>\r
+ <p><%= link_to l(:label_ldap_user_administration), :controller => "ldap_users", :action => "index" %></p>\r
+<% end %>\r
+\r
+<% labelled_tabular_form_for :redmine_le_setting, @setting, :url => {:action => 'update'}, :html => {:method => :put} do |f| %>\r
+ <%= f.error_messages %>\r
+\r
+<% if RedmineLeSetting.use_external_ldap %>\r
+ <h3><%= l(:label_change_admin_account) %></h3>\r
+ <div class="box">\r
+ <p><%= f.text_field :admin_account, :required => true, :size => 25 %></p>\r
+ <p><%= f.password_field :admin_password, :required => true, :size => 25 %></p>\r
+ </div>\r
+<% end %>\r
+\r
+ <h3><%= l(:label_smtp_setting) %></h3>\r
+ <div class="box">\r
+ <p><%= f.text_field :smtp_server, :size => 25 %></p>\r
+ <p><%= f.text_field :smtp_port, :size => 25, :label => l(:field_port) %></p>\r
+ <p><%= f.text_field :smtp_sender, :size => 25, :label => l(:setting_mail_from) %></p>\r
+ <p><%= f.text_field :smtp_user, :size => 25 %></p>\r
+ <p><%= f.password_field :smtp_password, :size => 25, :label => l(:field_password) %></p>\r
+ </div>\r
+\r
+ <%= f.submit l(:button_save) %>\r
+<% end %>\r
+\r
+<% html_title "RedmineLE" %>\r
--- /dev/null
+.redmine-le {\r
+ background-image: url(../images/redmine_le.png);\r
+}\r
--- /dev/null
+en:
+ label_ldap_user: "LDAP User"
+ label_ldap_user_plural: "LDAP Users"
+ label_ldap_user_administration: "LDAP User Administration"
+ label_change_admin_account: "Change administrator account"
+ label_smtp_setting: "SMTP setting"
+
+ warning_need_to_restart: "Please restart services to enable configuration changes."
+ error_failed_to_create_redmine_user: "Failed to create Redmine user"
+ error_failed_to_update_redmine_user: "Failed to update Redmine user"
+
+ field_admin_account: "Administrator account"
+ field_admin_password: "Administrator password"
+ field_smtp_server: "SMTP Server"
+ field_smtp_user: "Username"
--- /dev/null
+ja:
+ label_ldap_user: "LDAPユーザ"
+ label_ldap_user_plural: "LDAPユーザ"
+ label_ldap_user_administration: "LDAPユーザ管理"
+ label_change_admin_account: "管理者アカウントの変更"
+ label_smtp_setting: "SMTP設定"
+
+ warning_need_to_restart: "変更を反映するためサービスを再起動してください"
+ error_failed_to_create_redmine_user: "Redmineユーザの作成に失敗しました"
+ error_failed_to_update_redmine_user: "Redmineユーザの更新に失敗しました"
+
+ field_admin_account: "管理者アカウント"
+ field_admin_password: "管理者パスワード"
+ field_smtp_server: "SMTPサーバ"
+ field_smtp_user: "ユーザ名"
--- /dev/null
+ActionController::Routing::Routes.draw do |map|\r
+ map.resources :ldap_users\r
+\r
+ # override the route\r
+ map.connect 'settings/plugin/redmine_le', :controller => 'redmine_le_settings', :action => 'index'\r
+end\r
--- /dev/null
+class CreateRedmineLeSettings < ActiveRecord::Migration\r
+ def self.up\r
+ create_table :redmine_le_settings do |t|\r
+ t.boolean :use_external_ldap, :null => false\r
+ t.integer :auth_source_id\r
+ t.string :admin_account\r
+ t.string :admin_password\r
+ end\r
+ end\r
+\r
+ def self.down\r
+ drop_table :redmine_le_settings\r
+ end\r
+end\r
--- /dev/null
+require 'redmine'\r
+require 'redmine_le'\r
+\r
+require 'dispatcher'\r
+Dispatcher.to_prepare do\r
+ RedmineLe.apply_patch\r
+end\r
+\r
+Redmine::Plugin.register :redmine_le do\r
+ name 'RedmineLE plugin'\r
+ author 'Akihiro Ono'\r
+ description 'Extensions for RedmineLE'\r
+ version '0.0.1'\r
+\r
+ menu :admin_menu, :redmine_le, {\r
+ :controller => 'redmine_le_settings', :action => 'index'\r
+ }, :caption => 'RedmineLE'\r
+\r
+ # HACK: for showing configure link\r
+ settings(:partial => true)\r
+end\r
--- /dev/null
+require 'redmine_le/hooks'\r
+require 'redmine_le/project_patch'\r
+\r
+module RedmineLe\r
+ HOME = File.dirname(RAILS_ROOT)\r
+ HTTP_PORT = YAML.load_file(HOME + "/config/service.yml")["apache"]["port"]\r
+ TEMPLATE_DIR = File.dirname(File.dirname(__FILE__)) + "/template"\r
+\r
+ def self.apply_patch\r
+ Project.send(:include, ProjectPatch)\r
+ end\r
+end\r
--- /dev/null
+module RedmineLe\r
+ class Hooks < Redmine::Hook::ViewListener\r
+ def view_layouts_base_html_head(context)\r
+ # Engines doesn't support relative_url_root \r
+ #stylesheet_link_tag 'redmine_le', :plugin => 'redmine_le'\r
+ stylesheet_link_tag(context[:controller].relative_url_root.to_s +\r
+ '/plugin_assets/redmine_le/stylesheets/redmine_le.css'\r
+ )\r
+ end\r
+ end\r
+end\r
--- /dev/null
+require_dependency 'project'\r
+\r
+module RedmineLe\r
+ module ProjectPatch\r
+ def self.included(base)\r
+ base.extend(ClassMethods)\r
+ base.send(:include, InstanceMethods)\r
+\r
+ base.class_eval do\r
+ unloadable\r
+ after_create :setup_integration\r
+ after_destroy :cleanup_integration\r
+ end\r
+ end\r
+\r
+ module ClassMethods\r
+ end\r
+\r
+ module InstanceMethods\r
+ def repository_available?\r
+ module_enabled?(:repository) &&\r
+ (repository.nil? || repository.url == repository_url)\r
+ end\r
+\r
+ def repository_path\r
+ @repository_path ||=\r
+ File.join(RedmineLe::HOME, "subversion/repos", identifier)\r
+ end\r
+\r
+ def repository_url\r
+ @repository_url ||=\r
+ "http://localhost:#{RedmineLe::HTTP_PORT}/svn/#{identifier}"\r
+ end\r
+\r
+ def hook_config\r
+ @hook_config ||= HookConfig.new(self)\r
+ end\r
+\r
+ def setup_repository\r
+ begin\r
+ raise unless repository_available?\r
+ unless File.directory?(repository_path)\r
+ system(%Q[svnadmin create "#{repository_path}"])\r
+ root = "file:///" + repository_path.sub(/^\//, "")\r
+ system(%Q[svn mkdir "#{root}/trunk" "#{root}/branches" "#{root}/tags" -m "Initial repository layout"])\r
+ end\r
+ rescue\r
+ raise "Cannot create repository" \r
+ end\r
+\r
+ self.repository = Repository::Subversion.new(\r
+ :url => repository_url,\r
+ :root_url => repository_url,\r
+ :login => RedmineLeSetting.admin_account,\r
+ :password => RedmineLeSetting.admin_password\r
+ )\r
+\r
+ %w[pre-commit.bat post-commit.bat].each {|filename|\r
+ File.open(repository_path + "/hooks/#{filename}", "w") {|f|\r
+ f.print(ERB.new(File.read(RedmineLe::TEMPLATE_DIR +\r
+ "/#{filename}.erb")).result(binding))\r
+ }\r
+ }\r
+ end\r
+\r
+ def setup_job\r
+ ldap = AuthSourceLdap.first\r
+ url = repository_url\r
+ auth_token = RedmineLe::Utils.random_string(20)\r
+ data = ERB.new(File.read(RedmineLe::TEMPLATE_DIR + "/hudson_job_config.xml.erb")).result(binding)\r
+\r
+ Net::HTTP.start("localhost", RedmineLe::HTTP_PORT) {|http|\r
+ response = http.post("/hudson/createItem?name=#{identifier}", data, {\r
+ "Content-Type" => "application/xml"\r
+ })\r
+ raise "Cannot create Hudson job" unless response.code == "200"\r
+ }\r
+\r
+ hook_config["post_commit"]["perform_build"]["jobs"].push({\r
+ "name" => identifier,\r
+ "path" => "trunk"\r
+ })\r
+ hook_config.save\r
+ end\r
+\r
+ private\r
+ def setup_integration\r
+ return unless module_enabled?(:repository)\r
+\r
+ setup_repository\r
+ setup_job\r
+ end\r
+\r
+ def cleanup_integration\r
+ FileUtils.rm_rf(repository_path)\r
+ Net::HTTP.start("localhost", RedmineLe::HTTP_PORT) {|http|\r
+ http.post("/hudson/job/#{identifier}/doDelete", nil)\r
+ }\r
+ end\r
+ end\r
+ end\r
+end\r
--- /dev/null
+module RedmineLe\r
+ module Utils\r
+ CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"\r
+\r
+ def self.random_string(length)\r
+ length.times.map{CHARSET[rand(CHARSET.length), 1]}.join\r
+ end\r
+ end\r
+end\r
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+<project>
+ <actions/>
+ <description></description>
+ <keepDependencies>false</keepDependencies>
+ <properties/>
+ <scm class="hudson.scm.SubversionSCM">
+ <locations>
+ <hudson.scm.SubversionSCM_-ModuleLocation>
+ <remote><%= url %>/trunk</remote>
+ </hudson.scm.SubversionSCM_-ModuleLocation>
+ </locations>
+ <useUpdate>true</useUpdate>
+ <excludedRegions></excludedRegions>
+ <excludedUsers></excludedUsers>
+ <excludedRevprop></excludedRevprop>
+ </scm>
+ <canRoam>true</canRoam>
+ <disabled>false</disabled>
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
+ <authToken><%= auth_token %></authToken>
+ <triggers class="vector"/>
+ <concurrentBuild>false</concurrentBuild>
+ <builders/>
+ <publishers/>
+ <buildWrappers/>
+</project>
--- /dev/null
+setlocal\r
+call "<%= RedmineLe::HOME %>/script/setenv.bat"\r
+set RUBYLIB=<%= RedmineLe::HOME %>/script/hooks\r
+ruby -e "require 'subversion_hook/post_commit'; SubversionHook::PostCommit.new('%1', '%2')"\r
--- /dev/null
+setlocal\r
+call "<%= RedmineLe::HOME %>/script/setenv.bat"\r
+set RUBYLIB=<%= RedmineLe::HOME %>/script/hooks\r
+ruby -e "require 'subversion_hook/pre_commit'; SubversionHook::PreCommit.new('%1', '%2')"\r
--- /dev/null
+# Load the normal Rails helper\r
+require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')\r
+\r
+# Ensure that we are using the temporary fixture path\r
+Engines::Testing.set_fixture_path\r