Commit 819f6945 authored by Francisco Juan's avatar Francisco Juan

removed redmine-gitolite plugin

parent 7bc67f4e
<?xml version="1.0" encoding="UTF-8"?>
<loadpath>
<pathentry path="" type="src"/>
<pathentry path="org.rubypeople.rdt.launching.RUBY_CONTAINER" type="con"/>
</loadpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>redmine-gitolite</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.rubypeople.rdt.core.rubybuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.rubypeople.rdt.core.rubynature</nature>
</natures>
</projectDescription>
= Patches
* work with gitolite
* support subproject git repo. (e.g. git@site.name:parent_project/subproject.git)
* fix bugs.
= Redmine Gitolite
A Redmine plugin which manages your gitolite configuration based on your projects and memberships in Redmine. Includes Public Key management views (extracted from http://plan.io).
This plugin was originally developed by Jan Schulz-Hofen for http://plan.io. Several updates/fixes were provided by github users untoldwind, tingar and ericpaulbishop. These updates were merged together and expanded upon by Eric Bishop.
In order to use this plugin you must have the following gems installed:
lockfile
inifile
net-ssh
== Copyright & License
Copyright (c) 2009-2010 Jan Schulz-Hofen, ROCKET RENTALS GmbH (http://www.rocket-rentals.de). MIT License.
Copyright (c) 2010 Eric Bishop (ericpaulbishop@gmail.com) MIT License.
class GitolitePublicKeysController < ApplicationController
unloadable
before_filter :require_login
before_filter :set_user_variable
before_filter :find_gitolite_public_key, :except => [:index, :new, :create]
def index
@status = if (session[:gitolite_public_key_filter_status]=params[:status]).nil?
GitolitePublicKey::STATUS_ACTIVE
elsif params[:status].blank?
nil
else
params[:status] == "true"
end
c = ARCondition.new(!@status.nil? ? ["active=?", @status] : nil)
@gitolite_public_keys = @user.gitolite_public_keys.all(:order => 'active DESC, created_at DESC', :conditions => c.conditions)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => @gitolite_public_keys }
end
end
def edit
end
def update
if @gitolite_public_key.update_attributes(params[:public_key])
flash[:notice] = l(:notice_public_key_updated)
redirect_to url_for(:action => 'index', :status => session[:gitolite_public_key_filter_status])
else
render :action => 'edit'
end
end
def new
@gitolite_public_key = GitolitePublicKey.new(:user => @user)
end
def create
@gitolite_public_key = GitolitePublicKey.new(params[:public_key].merge(:user => @user))
if @gitolite_public_key.save
flash[:notice] = l(:notice_public_key_added)
redirect_to url_for(:action => 'index', :status => session[:gitolite_public_key_filter_status])
else
render :action => 'new'
end
end
def show
respond_to do |format|
format.html # show.html.erb
format.json { render :json => @gitolite_public_key }
end
end
protected
def set_user_variable
@user = User.current
end
def find_gitolite_public_key
key = GitolitePublicKey.find_by_id(params[:id])
if key and key.user == @user
@gitolite_public_key = key
elsif key
render_403
else
render_404
end
end
end
module GitolitePublicKeysHelper
def gitolite_public_keys_status_options_for_select(user, selected)
key_count_by_active = user.gitolite_public_keys.count(:group => 'active').to_hash
options_for_select([[l(:label_all), nil],
["#{l(:status_active)} (#{key_count_by_active[true].to_i})", GitolitePublicKey::STATUS_ACTIVE],
["#{l(:status_locked)} (#{key_count_by_active[false].to_i})", GitolitePublicKey::STATUS_LOCKED]], selected)
end
end
\ No newline at end of file
class GitoliteObserver < ActiveRecord::Observer
observe :project, :user, :gitolite_public_key, :member, :role, :repository
# def before_create(object)
# if object.is_a?(Project)
# repo = Repository::Git.new
# repo.url = repo.root_url = File.join(Gitolite::GITOSIS_BASE_PATH,"#{object.identifier}.git")
# object.repository = repo
# end
# end
def after_save(object) ; update_repositories(object) ; end
def after_destroy(object) ; update_repositories(object) ; end
protected
def update_repositories(object)
case object
when Repository then Gitolite::update_repositories(object.project)
when User then Gitolite::update_repositories(object.projects) unless is_login_save?(object)
when GitolitePublicKey then Gitolite::update_repositories(object.user.projects)
when Member then Gitolite::update_repositories(object.project)
when Role then
Gitolite::update_repositories(object.members.map(&:project).uniq.compact) rescue nil
end
end
private
# Test for the fingerprint of changes to the user model when the User actually logs in.
def is_login_save?(user)
user.changed? && user.changed.length == 2 && user.changed.include?("updated_on") && user.changed.include?("last_login_on")
end
end
class GitolitePublicKey < ActiveRecord::Base
STATUS_ACTIVE = 1
STATUS_LOCKED = 0
belongs_to :user
validates_uniqueness_of :title, :scope => :user_id
validates_uniqueness_of :identifier, :score => :user_id
validates_presence_of :title, :key, :identifier
named_scope :active, {:conditions => {:active => GitolitePublicKey::STATUS_ACTIVE}}
named_scope :inactive, {:conditions => {:active => GitolitePublicKey::STATUS_LOCKED}}
validate :has_not_been_changed
before_validation :set_identifier
def has_not_been_changed
unless new_record?
%w(identifier key user_id).each do |attribute|
errors.add(attribute, 'may not be changed') unless changes[attribute].blank?
end
end
end
def set_identifier
# TODO: some better naming, id is set long AFTER this method is called. Maybe timestamp?
self.identifier ||= "#{self.user.login.underscore}@#{self.title.underscore}".gsub(/[^0-9a-zA-Z-_@]/,'_')
end
def to_s ; title ; end
end
<div class="box tabular">
<p><%= f.text_field :title, :required => true %></p>
<p><%= f.text_area :key, :required => true, :disabled => !@gitolite_public_key.new_record?, :style => 'width:99%;height:140px;', :label => :field_public_key %>
<% if !@gitolite_public_key.new_record?%>
<br/><em><%= l(:label_key_cannot_be_changed_please_create_new_key) %></em>
<% end %>
</p>
<p><%= f.check_box :active %></p>
</div>
<h2><%= link_to l(:label_public_keys), public_keys_path %> &#187; <%= h @gitolite_public_key %></h2>
<%= error_messages_for :gitolite_public_key %>
<% form_for :public_key, @gitolite_public_key, :url => { :action => "update" }, :html => { :method => :put},
:builder => TabularFormBuilder,
:lang => current_language do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'my/sidebar' %>
<% end %>
<% html_title(l(:label_public_keys)) -%>
<h2><%= link_to l(:label_my_account), :controller => 'my', :action => 'account' %> &#187; <%=l(:label_public_keys)%></h2>
<% form_tag({}, :method => :get) do %>
<fieldset><legend><%= l(:label_filter_plural) %></legend>
<label><%= l(:field_status) %>:</label>
<%= select_tag 'status', gitolite_public_keys_status_options_for_select(@user, @status), :class => "small", :onchange => "this.form.submit(); return false;" %>
<%= submit_tag l(:button_apply), :class => "small", :name => nil %>
</fieldset>
<% end %>
&nbsp;
<% if @gitolite_public_keys.any? %>
<table class="list">
<tr>
<th><%= l(:field_name) %></th>
<th><%= l(:field_created_on) %></th>
<th style="width:15%;"><%= l(:field_active) %></th>
<th align="center" style="width:10%;"> </th>
</tr>
<% @gitolite_public_keys.each do |key| %>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= link_to h(key), :action => 'edit', :id => key %></td>
<td><%= format_time(key.created_at) %></td>
<td class="center" style="width:15%;"><%= image_tag('true.png') if key.active? %></td>
<td class="buttons">
<%= link_to l(key.active? ? :button_lock : :button_unlock), public_key_path(key, :public_key => {:active => key.active? ? GitolitePublicKey::STATUS_LOCKED : GitolitePublicKey::STATUS_ACTIVE}), :method => :put, :class => "icon #{key.active? ? 'icon-lock' : 'icon-unlock'}" %>
</td>
</tr>
<% end %>
</table>
<% end %>
<p><%= link_to l(:label_enumeration_new), { :action => 'new'} %></p>
<% html_title(l(:label_public_keys)) -%>
<h2><%= link_to l(:label_public_keys), public_keys_path %> &#187; <%=l(:label_public_key_new)%></h2>
<%= error_messages_for :gitolite_public_key %>
<% form_for :public_key, @gitolite_public_key, :url => { :action => "create" },
:builder => TabularFormBuilder,
:lang => current_language do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= submit_tag l(:button_create) %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'my/sidebar' %>
<% end %>
<% html_title(l(:label_public_keys)) -%>
<%# This is used to display basic git setup instructions, like on github... %>
<% flash.now[:error] = "Repository does not exist. Create one using the instructions below." %>
<div class="box">
<h2>Git Setup:</h2>
<pre> <a href="http://git-scm.com/download" target="_blank">Download and Install Git</a>
git config --global user.name "<%= User.current.login %>"
git config --global user.email <%= User.current.mail %>
</pre>
<h2>Permission Setup:</h2>
<pre> <%= link_to "Upload SSH Public Key", {:controller => 'my', :action => 'public_keys'} %>
Add yourself as a project developer: <%= link_to @project.name + " Settings", {:controller => 'projects', :action => 'settings'} %> -&gt; Members Tab -&gt; New Member
</pre>
<h2>Repository Setup:</h2>
<pre> mkdir <%= @project.identifier %>
cd <%= @project.identifier %>
git init
touch README
git add .
git commit -m 'Initializing <%= @project %> repository'
git remote add origin <%= Setting.plugin_redmine_gitolite['developerBaseUrls'] + Gitolite.repository_name(@project) + '.git' %>
git push origin master
</pre>
<h2>Existing Git Repo?</h2>
<pre> cd existing_git_repo
git remote add origin <%= Setting.plugin_redmine_gitolite['developerBaseUrls'] + Gitolite.repository_name(@project) + '.git' %>
git push origin master
</pre>
</div>
<div class="tabular settings">
<p>
<label><%= l(:label_gitolite_url)%></label>
<%= text_field_tag("settings[gitoliteUrl]", @settings['gitoliteUrl'], :size => 60) %>
<br />
</p>
<p>
<label><%= l(:label_gitolite_identity_file)%></label>
<%= text_field_tag("settings[gitoliteIdentityFile]", @settings['gitoliteIdentityFile'], :size => 60) %>
<br />
</p>
<p>
<label><%= l(:label_base_path)%></label>
<%= text_field_tag("settings[basePath]", @settings['basePath'], :size => 60) %>
<br />
</p>
<p>
<label><%= l(:label_developer_base_urls)%></label>
<%= text_area_tag("settings[developerBaseUrls]", @settings['developerBaseUrls'].split(/[\r\n\t ,;]+/).join("\n"), :size => 60) %>
<br />
</p>
<p>
<label><%= l(:label_read_only_base_urls)%></label>
<%= text_area_tag("settings[readOnlyBaseUrls]", @settings['readOnlyBaseUrls'].split(/[\r\n\t ,;]+/).join("\n"), :size => 60) %>
<br />
</p>
</div>
'bg':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'bs':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'ca':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'cs':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'da':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'de':
label_public_keys: Öffentliche Schlüssel
label_public_key_new: Neuer öffentlicher Schlüssel
field_public_key: Schlüssel
notice_public_key_updated: Öffentlicher Schlüssel wurde erfolgreich aktualisiert.
notice_public_key_added: Öffentlicher Schlüssel wurde erfolgreich hinzugefügt.
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
label_key_cannot_be_changed_please_create_new_key: 'Der Schlüssel kann nicht mehr verändert werden. Sie können jedoch diesen Schlüssel deaktivieren und einen neuen anlegen.'
activerecord:
errors:
messages:
'may not be changed': "darf nicht verändert werden"
'el':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'en':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'es':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'fi':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'fr':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'gl':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'he':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'hu':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'id':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'it':
label_public_keys: Chiavi pubbliche
label_public_key_new: Nuova chiave pubblica
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Chiave
notice_public_key_updated: Chiave pubblica aggiornata.
notice_public_key_added: Chiave pubblica aggiunta.
label_key_cannot_be_changed_please_create_new_key: 'La chiave non può essere aggiornata. È comunque possibile disattivarla e crearne una nuova.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'ja':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'ko':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'lt':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'nl':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'no':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'pl':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'pt-BR':
label_public_keys: Chaves pblicas
label_public_key_new: Nova chave pblica
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Arquivo de identificao do Gitolite
label_base_path: Caminho de base
label_developer_base_urls: URL(s) base de Desenvolvedor
label_read_only_base_urls: URL(s) base de Apenas-leitura
field_public_key: Chave
notice_public_key_updated: Chave pblica foi atualizada com sucesso.
notice_public_key_added: Chave pblica foi atualizada com sucesso.
label_key_cannot_be_changed_please_create_new_key: 'A chave no poder ser alterada. Mas voc ainda pode desativa-la e criar uma nova.'
activerecord:
errors:
messages:
'may not be changed': 'no dever ser alterado'
'pt':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'ro':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'ru':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'sk':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'sl':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'sr':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'sv':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'th':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'tr':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'uk':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'vi':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'zh-TW':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
'zh':
label_public_keys: Public keys
label_public_key_new: New public key
label_gitolite_url: Gitolite URL
label_gitolite_identity_file: Gitolite identity file
label_base_path: Base path
label_developer_base_urls: Developer base URL(s)
label_read_only_base_urls: Read-only base URL(s)
field_public_key: Key
notice_public_key_updated: Public key was successfully updated.
notice_public_key_added: Public key was successfully added.
label_key_cannot_be_changed_please_create_new_key: 'The key cannot be altered anymore. However, you can deactivate it and create a new one.'
activerecord:
errors:
messages:
'may not be changed': 'may not be changed'
if defined? map
map.resources :public_keys, :controller => 'gitolite_public_keys', :path_prefix => 'my'
else
ActionController::Routing::Routes.draw do |map|
map.resources :public_keys, :controller => 'gitolite_public_keys', :path_prefix => 'my'
end
end
\ No newline at end of file
class CreateGitolitePublicKeys < ActiveRecord::Migration
def self.up
create_table :gitolite_public_keys do |t|
t.column :title, :string
t.column :identifier, :string
t.column :key, :text
t.column :active, :integer, :default => 1
t.references :user
t.timestamps
end
end
def self.down
drop_table :gitolite_public_keys
end
end
require 'redmine'
require_dependency 'principal'
require_dependency 'user'
require_dependency 'gitolite'
require_dependency 'gitolite/patches/repositories_controller_patch'
require_dependency 'gitolite/patches/repositories_helper_patch'
require_dependency 'gitolite/patches/git_adapter_patch'
Redmine::Plugin.register :redmine_gitolite do
name 'Redmine Gitolite plugin'
author 'Christian Käser, Zsolt Parragi, Yunsang Choi, Joshua Hogendorn, Jan Schulz-Hofen and others'
description 'Enables Redmine to update a gitolite server.'
version '0.1.0'
settings :default => {
'gitoliteUrl' => 'git@localhost:gitolite-admin.git',
'gitoliteIdentityFile' => '/srv/projects/redmine/miner/.ssh/id_rsa',
'developerBaseUrls' => 'git@www.salamander-linux.com:,https://[user]@www.salamander-linux.com/git/',
'readOnlyBaseUrls' => 'http://www.salamander-linux.com/git/',
'basePath' => '/srv/projects/git/repositories/',
},
:partial => 'redmine_gitolite'
end
# initialize hook
class GitolitePublicKeyHook < Redmine::Hook::ViewListener
render_on :view_my_account_contextual, :inline => "| <%= link_to(l(:label_public_keys), public_keys_path) %>"
end
# initialize association from user -> public keys
User.send(:has_many, :gitolite_public_keys, :dependent => :destroy)
# initialize observer
ActiveRecord::Base.observers = ActiveRecord::Base.observers << GitoliteObserver
require 'lockfile'
require 'net/ssh'
require 'tmpdir'
require 'gitolite_conf.rb'
module Gitolite
def self.repository_name project
parent_name = project.parent ? repository_name(project.parent) : ""
return "#{parent_name}/#{project.identifier}".sub(/^\//, "")
end
def self.get_urls(project)
urls = {:read_only => [], :developer => []}
read_only_baseurls = Setting.plugin_redmine_gitolite['readOnlyBaseUrls'].split(/[\r\n\t ,;]+/)
developer_baseurls = Setting.plugin_redmine_gitolite['developerBaseUrls'].split(/[\r\n\t ,;]+/)
project_path = repository_name(project) + ".git"
read_only_baseurls.each {|baseurl| urls[:read_only] << baseurl + project_path}
developer_baseurls.each {|baseurl| urls[:developer] << baseurl + project_path}
return urls
end
def self.update_repositories(projects)
projects = (projects.is_a?(Array) ? projects : [projects])
if(defined?(@recursionCheck))
if(@recursionCheck)
return
end
end
@recursionCheck = true
# Don't bother doing anything if none of the projects we've been handed have a Git repository
unless projects.detect{|p| p.repository.is_a?(Repository::Git) }.nil?
lockfile=File.new(File.join(RAILS_ROOT,"tmp",'redmine_gitolite_lock'),File::CREAT|File::RDONLY)
retries=5
loop do
break if lockfile.flock(File::LOCK_EX|File::LOCK_NB)
retries-=1
sleep 2
raise Lockfile::MaxTriesLockError if retries<=0
end
# HANDLE GIT
# create tmp dir
local_dir = File.join(RAILS_ROOT, "tmp","redmine_gitolite_#{Time.now.to_i}")
%x[mkdir "#{local_dir}"]
# Create GIT_SSH script
ssh_with_identity_file = File.join(local_dir, 'ssh_with_identity_file.sh')
File.open(ssh_with_identity_file, "w") do |f|
f.puts "#!/bin/bash"
f.puts "exec ssh -o stricthostkeychecking=no -i #{Setting.plugin_redmine_gitolite['gitoliteIdentityFile']} \"$@\""
end
File.chmod(0755, ssh_with_identity_file)
# clone repo
%x[env GIT_SSH=#{ssh_with_identity_file} git clone #{Setting.plugin_redmine_gitolite['gitoliteUrl']} #{local_dir}/gitolite]
conf = Config.new(File.join(local_dir, 'gitolite', 'conf', 'gitolite.conf'))
changed = false
projects.select{|p| p.repository.is_a?(Repository::Git)}.each do |project|
# fetch users
users = project.member_principals.map(&:user).compact.uniq
write_users = users.select{ |user| user.allowed_to?( :commit_access, project ) }
read_users = users.select{ |user| user.allowed_to?( :view_changesets, project ) && !user.allowed_to?( :commit_access, project ) }
# write key files
users.map{|u| u.gitolite_public_keys.active}.flatten.compact.uniq.each do |key|
filename = File.join(local_dir, 'gitolite/keydir',"#{key.identifier}.pub")
unless File.exists? filename
File.open(filename, 'w') {|f| f.write(key.key.gsub(/\n/,'')) }
changed = true
end
end
# delete inactives
users.map{|u| u.gitolite_public_keys.inactive}.flatten.compact.uniq.each do |key|
filename = File.join(local_dir, 'gitolite/keydir',"#{key.identifier}.pub")
if File.exists? filename
File.unlink() rescue nil
changed = true
end
end
# write config file
repo_name = repository_name(project)
read_users = read_users.map{|u| u.login.underscore}
write_users = write_users.map{|u| u.login.underscore}
conf.set_read_user repo_name, read_users
conf.set_write_user repo_name, write_users
# TODO: gitweb and git daemon support!
end
if conf.changed?
conf.save
changed = true
end
if changed
git_push_file = File.join(local_dir, 'git_push.sh')
new_dir= File.join(local_dir,'gitolite')
File.open(git_push_file, "w") do |f|
f.puts "#!/bin/sh"
f.puts "cd #{new_dir}"
f.puts "git add keydir/*"
f.puts "git add conf/gitolite.conf"
f.puts "git config user.email '#{Setting.mail_from}'"
f.puts "git config user.name 'Redmine'"
f.puts "git commit -a -m 'updated by Redmine Gitolite'"
f.puts "GIT_SSH=#{ssh_with_identity_file} git push"
end
File.chmod(0755, git_push_file)
# add, commit, push, and remove local tmp dir
%x[sh #{git_push_file}]
end
# remove local copy
%x[rm -Rf #{local_dir}]
lockfile.flock(File::LOCK_UN)
end
@recursionCheck = false
end
end
require_dependency 'redmine/scm/adapters/git_adapter'
module Gitolite
module Patches
module GitAdapterPatch
def self.included(base)
base.class_eval do
unloadable
end
base.send(:alias_method_chain, :lastrev, :time_fixed)
base.send(:alias_method_chain, :revisions, :time_fixed)
end
GIT_BIN = "git"
def lastrev_with_time_fixed(path,rev)
return nil if path.nil?
cmd = "#{GIT_BIN} --git-dir #{target('')} log --pretty=fuller --date=rfc --no-merges -n 1 "
cmd << " #{shell_quote rev} " if rev
cmd << "-- #{path} " unless path.empty?
shellout(cmd) do |io|
begin
id = io.gets.split[1]
author = io.gets.match('Author:\s+(.*)$')[1]
2.times { io.gets }
time = io.gets.match('CommitDate:\s+(.*)$')[1]
Redmine::Scm::Adapters::Revision.new({
:identifier => id,
:scmid => id,
:author => author,
:time => Time.rfc2822(time),
:message => nil,
:paths => nil
})
rescue NoMethodError => e
logger.error("The revision '#{path}' has a wrong format")
return nil
end
end
end
def revisions_with_time_fixed(path, identifier_from, identifier_to, options={})
revisions = Redmine::Scm::Adapters::Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=rfc --pretty=fuller"
cmd << " --reverse" if options[:reverse]
cmd << " --all" if options[:all]
cmd << " -n #{options[:limit]} " if options[:limit]
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
cmd << " #{shell_quote identifier_to} " if identifier_to
cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
cmd << " -- #{path}" if path && !path.empty?
shellout(cmd) do |io|
files=[]
changeset = {}
parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
revno = 1
io.each_line do |line|
if line =~ /^commit ([0-9a-f]{40})$/
key = "commit"
value = $1
if (parsing_descr == 1 || parsing_descr == 2)
parsing_descr = 0
revision = Redmine::Scm::Adapters::Revision.new({
:identifier => changeset[:commit],
:scmid => changeset[:commit],
:author => changeset[:author],
#:time => Time.parse(changeset[:date]),
:time => Time.rfc2822(changeset[:date]),
:message => changeset[:description],
:paths => files
})
if block_given?
yield revision
else
revisions << revision
end
changeset = {}
files = []
revno = revno + 1
end
changeset[:commit] = $1
elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
key = $1
value = $2
if key == "Author"
changeset[:author] = value
elsif key == "CommitDate"
changeset[:date] = value
end
elsif (parsing_descr == 0) && line.chomp.to_s == ""
parsing_descr = 1
changeset[:description] = ""
elsif (parsing_descr == 1 || parsing_descr == 2) \
&& line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\s+(.+)$/
parsing_descr = 2
fileaction = $1
filepath = $2
files << {:action => fileaction, :path => filepath}
elsif (parsing_descr == 1 || parsing_descr == 2) \
&& line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\s+(.+)$/
parsing_descr = 2
fileaction = $1
filepath = $3
files << {:action => fileaction, :path => filepath}
elsif (parsing_descr == 1) && line.chomp.to_s == ""
parsing_descr = 2
elsif (parsing_descr == 1)
changeset[:description] << line[4..-1]
end
end
if changeset[:commit]
revision = Redmine::Scm::Adapters::Revision.new({
:identifier => changeset[:commit],
:scmid => changeset[:commit],
:author => changeset[:author],
:time => Time.rfc2822(changeset[:date]),
:message => changeset[:description],
:paths => files
})
if block_given?
yield revision
else
revisions << revision
end
end
end
return nil if $? && $?.exitstatus != 0
revisions
end
end
end
end
Redmine::Scm::Adapters::GitAdapter.send(:include, Gitolite::Patches::GitAdapterPatch) unless Redmine::Scm::Adapters::GitAdapter.include?(Gitolite::Patches::GitAdapterPatch)
require_dependency 'repositories_controller'
module Gitolite
module Patches
module RepositoriesControllerPatch
def show_with_git_instructions
if @repository.is_a?(Repository::Git) and @repository.entries(@path, @rev).blank?
render :action => 'git_instructions'
else
show_without_git_instructions
end
end
def edit_with_scm_settings
params[:repository] ||= {}
if(@project.parent)
params[:repository][:url] = File.join(Setting.plugin_redmine_gitolite['basePath'],@project.parent.identifier,"#{@project.identifier}.git") if params[:repository_scm] == 'Git'
else
params[:repository][:url] = File.join(Setting.plugin_redmine_gitolite['basePath'],"#{@project.identifier}.git") if params[:repository_scm] == 'Git'
end
edit_without_scm_settings
end
def self.included(base)
base.class_eval do
unloadable
end
base.send(:alias_method_chain, :show, :git_instructions)
base.send(:alias_method_chain, :edit, :scm_settings)
end
end
end
end
RepositoriesController.send(:include, Gitolite::Patches::RepositoriesControllerPatch) unless RepositoriesController.include?(Gitolite::Patches::RepositoriesControllerPatch)
require_dependency 'repositories_helper'
module Gitolite
module Patches
module RepositoriesHelperPatch
def git_field_tags_with_disabled_configuration(form, repository) ; '' ; end
def self.included(base)
base.class_eval do
unloadable
end
base.send(:alias_method_chain, :git_field_tags, :disabled_configuration)
end
end
end
end
RepositoriesHelper.send(:include, Gitolite::Patches::RepositoriesHelperPatch) unless RepositoriesHelper.include?(Gitolite::Patches::RepositoriesHelperPatch)
\ No newline at end of file
module Gitolite
class Config
def initialize file_path
@path = file_path
load
end
def save
File.open(@path, "w") do |f|
f.puts content
end
@original_content = content
end
def add_write_user repo_name, users
repository(repo_name).add "RW+", users
end
def set_write_user repo_name, users
repository(repo_name).set "RW+", users
end
def add_read_user repo_name, users
repository(repo_name).add "R", users
end
def set_read_user repo_name, users
repository(repo_name).set "R", users
end
def changed?
@original_content != content
end
private
def load
@original_content = []
@repositories = {}
cur_repo_name = nil
File.open(@path).each_line do |line|
@original_content << line
tokens = line.strip.split
if tokens.first == 'repo'
cur_repo_name = tokens.last
@repositories[cur_repo_name] = AccessRights.new
next
end
cur_repo_right = @repositories[cur_repo_name]
if cur_repo_right and tokens[1] == '='
cur_repo_right.add tokens.first, tokens[2..-1]
end
end
@original_content = @original_content.join
end
def repository repo_name
@repositories[repo_name] ||= AccessRights.new
end
def content
content = []
@repositories.each do |repo, rights|
content << "repo\t#{repo}"
rights.each do |perm, users|
content << "\t#{perm}\t=\t#{users.join(' ')}" if users.length > 0
end
content << ""
end
return content.join("\n")
end
end
class AccessRights
def initialize
@rights = {}
end
def add perm, users
@rights[perm.to_sym] ||= []
@rights[perm.to_sym] << users
@rights[perm.to_sym].flatten!
@rights[perm.to_sym].uniq!
end
def set perm, users
@rights[perm.to_sym] = []
add perm, users
end
def each
@rights.each {|k,v| yield k, v}
end
end
end
namespace :gitolite do
desc "update gitolite repositories"
task :update_repositories => [:environment] do
projects = Project.active
puts "Updating repositories for projects #{projects.join(' ')}"
Gitolite.update_repositories(projects)
end
desc "fetch commits from gitolite repositories"
task :fetch_changes => [:environment] do
Repository.fetch_changesets
end
end
\ No newline at end of file
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
one:
id: 1
title: MyString
key: MyText
two:
id: 2
title: MyString
key: MyText
# Load the normal Rails helper
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
# Ensure that we are using the temporary fixture path
Engines::Testing.set_fixture_path
require File.dirname(__FILE__) + '/../test_helper'
class GitolitePublicKeyTest < ActiveSupport::TestCase
fixtures :gitolite_public_keys
# Replace this with your real tests.
def test_truth
assert true
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment