# File app/roles/static_model.rb, line 7 +def primary_key + 'id' +end+
diff --git a/doc/app/Ability.html b/doc/app/Ability.html new file mode 100644 index 00000000..f780d067 --- /dev/null +++ b/doc/app/Ability.html @@ -0,0 +1,570 @@ + + + +
+ + +# File app/models/ability.rb, line 3 +def allowed(object, subject) + case subject.class.name + when "Project" then project_abilities(object, subject) + when "Issue" then issue_abilities(object, subject) + when "Note" then note_abilities(object, subject) + when "Snippet" then snippet_abilities(object, subject) + when "MergeRequest" then merge_request_abilities(object, subject) + else [] + end +end+
# File app/models/ability.rb, line 14 +def project_abilities(user, project) + rules = [] + + rules << [ + :read_project, + :read_wiki, + :read_issue, + :read_milestone, + :read_snippet, + :read_team_member, + :read_merge_request, + :read_note, + :write_project, + :write_issue, + :write_note + ] if project.guest_access_for?(user) + + rules << [ + :download_code, + :write_merge_request, + :write_snippet + ] if project.report_access_for?(user) + + rules << [ + :write_wiki, + :push_code + ] if project.dev_access_for?(user) + + rules << [ + :push_code_to_protected_branches + ] if project.master_access_for?(user) + + rules << [ + :modify_issue, + :modify_snippet, + :modify_merge_request, + :admin_project, + :admin_issue, + :admin_milestone, + :admin_snippet, + :admin_team_member, + :admin_merge_request, + :admin_note, + :accept_mr, + :admin_wiki + ] if project.master_access_for?(user) || project.owner == user + + rules.flatten +end+
Remove user from all projects and set blocked attribute to true
+ + + +# File app/roles/account.rb, line 47 +def block + users_projects.find_each do |membership| + return false unless membership.destroy + end + + self.blocked = true + save +end+
# File app/roles/account.rb, line 25 +def can_create_group? + is_admin? +end+
# File app/roles/account.rb, line 21 +def can_create_project? + projects_limit > my_own_projects.count +end+
# File app/roles/account.rb, line 37 +def cared_merge_requests + MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id).opened +end+
# File app/roles/account.rb, line 33 +def first_name + name.split.first unless name.blank? +end+
Returns a string for use as a Gitolite user identifier
+ +Note that Gitolite 2.x requires the following +pattern for users:
+ +^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$+ + + +
# File app/roles/account.rb, line 7 +def identifier + # Replace non-word chars with underscores, then make sure it starts with + # valid chars + email.gsub(%r\W/, '_').gsub(%r\A([\W\_])+/, '') +end+
# File app/roles/account.rb, line 13 +def is_admin? + admin +end+
# File app/roles/account.rb, line 29 +def last_activity_project + projects.first +end+
# File app/roles/account.rb, line 41 +def project_ids + projects.map(&:id) +end+
# File app/roles/account.rb, line 56 +def projects_limit_percent + return 100 if projects_limit.zero? + (my_own_projects.count.to_f / projects_limit) * 100 +end+
# File app/roles/account.rb, line 70 +def projects_with_events + projects.includes(:events).order("events.created_at DESC") +end+
# File app/roles/account.rb, line 61 +def recent_push project_id = nil + # Get push events not earlier than 2 hours ago + events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours) + events = events.where(project_id: project_id) if project_id + + # Take only latest one + events = events.recent.limit(1).first +end+
# File app/roles/account.rb, line 17 +def require_ssh_key? + keys.count == 0 +end+
ActiveRecord::Observer + +
# File app/observers/activity_observer.rb, line 4 +def after_create(record) + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event.determine_action(record), + author_id: record.author_id + ) +end+
# File app/observers/activity_observer.rb, line 14 +def after_save(record) + if record.changed.include?("closed") + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: (record.closed ? Event::Closed : Event::Reopened), + author_id: record.author_id_of_changes + ) + end +end+
AdminController + +
# File app/controllers/admin/dashboard_controller.rb, line 2 +def index + @workers = Resque.workers + @pending_jobs = Resque.size(:post_receive) + @projects = Project.order("created_at DESC").limit(10) + @users = User.order("created_at DESC").limit(10) +end+
AdminController + +
# File app/controllers/admin/groups_controller.rb, line 23 +def create + @group = Group.new(params[:group]) + @group.owner = current_user + + if @group.save + redirect_to [:admin, @group], notice: 'Group was successfully created.' + else + render action: "new" + end +end+
# File app/controllers/admin/groups_controller.rb, line 64 +def destroy + @group.destroy + + redirect_to admin_groups_path, notice: 'Group was successfully deleted.' +end+
# File app/controllers/admin/groups_controller.rb, line 20 +def edit +end+
# File app/controllers/admin/groups_controller.rb, line 4 +def index + @groups = Group.scoped + @groups = @groups.search(params[:name]) if params[:name].present? + @groups = @groups.page(params[:page]).per(20) +end+
# File app/controllers/admin/groups_controller.rb, line 16 +def new + @group = Group.new +end+
# File app/controllers/admin/groups_controller.rb, line 49 +def project_update + project_ids = params[:project_ids] + Project.where(id: project_ids).update_all(group_id: @group.id) + + redirect_to :back, notice: 'Group was successfully updated.' +end+
# File app/controllers/admin/groups_controller.rb, line 56 +def remove_project + @project = Project.find(params[:project_id]) + @project.group_id = nil + @project.save + + redirect_to :back, notice: 'Group was successfully updated.' +end+
# File app/controllers/admin/groups_controller.rb, line 10 +def show + @projects = Project.scoped + @projects = @projects.not_in_group(@group) if @group.projects.present? + @projects = @projects.all +end+
# File app/controllers/admin/groups_controller.rb, line 34 +def update + group_params = params[:group].dup + owner_id =group_params.delete(:owner_id) + + if owner_id + @group.owner = User.find(owner_id) + end + + if @group.update_attributes(group_params) + redirect_to [:admin, @group], notice: 'Group was successfully updated.' + else + render action: "edit" + end +end+
AdminController + +
# File app/controllers/admin/hooks_controller.rb, line 7 +def create + @hook = SystemHook.new(params[:hook]) + + if @hook.save + redirect_to admin_hooks_path, notice: 'Hook was successfully created.' + else + @hooks = SystemHook.all + render :index + end +end+
# File app/controllers/admin/hooks_controller.rb, line 18 +def destroy + @hook = SystemHook.find(params[:id]) + @hook.destroy + + redirect_to admin_hooks_path +end+
# File app/controllers/admin/hooks_controller.rb, line 2 +def index + @hooks = SystemHook.all + @hook = SystemHook.new +end+
# File app/controllers/admin/hooks_controller.rb, line 26 +def test + @hook = SystemHook.find(params[:hook_id]) + data = { + event_name: "project_create", + name: "Ruby", + path: "ruby", + project_id: 1, + owner_name: "Someone", + owner_email: "example@gitlabhq.com" + } + @hook.execute(data) + + redirect_to :back +end+
AdminController + +
AdminController + +
# File app/controllers/admin/projects_controller.rb, line 29 +def create + @admin_project = Project.new(params[:project]) + @admin_project.owner = current_user + + if @admin_project.save + redirect_to [:admin, @admin_project], notice: 'Project was successfully created.' + else + render action: "new" + end +end+
# File app/controllers/admin/projects_controller.rb, line 54 +def destroy + @admin_project.destroy + + redirect_to admin_projects_url, notice: 'Project was successfully deleted.' +end+
# File app/controllers/admin/projects_controller.rb, line 20 +def edit +end+
# File app/controllers/admin/projects_controller.rb, line 4 +def index + @admin_projects = Project.scoped + @admin_projects = @admin_projects.search(params[:name]) if params[:name].present? + @admin_projects = @admin_projects.page(params[:page]).per(20) +end+
# File app/controllers/admin/projects_controller.rb, line 16 +def new + @admin_project = Project.new +end+
# File app/controllers/admin/projects_controller.rb, line 10 +def show + @users = User.scoped + @users = @users.not_in_project(@admin_project) if @admin_project.users.present? + @users = @users.all +end+
# File app/controllers/admin/projects_controller.rb, line 23 +def team_update + @admin_project.add_users_ids_to_team(params[:user_ids], params[:project_access]) + + redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' +end+
# File app/controllers/admin/projects_controller.rb, line 40 +def update + owner_id = params[:project].delete(:owner_id) + + if owner_id + @admin_project.owner = User.find(owner_id) + end + + if @admin_project.update_attributes(params[:project]) + redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' + else + render action: "edit" + end +end+
AdminController + +
# File app/controllers/admin/resque_controller.rb, line 2 +def show +end+
AdminController + +
# File app/controllers/admin/team_members_controller.rb, line 16 +def destroy + @admin_team_member = UsersProject.find(params[:id]) + @admin_team_member.destroy + + redirect_to :back +end+
# File app/controllers/admin/team_members_controller.rb, line 2 +def edit + @admin_team_member = UsersProject.find(params[:id]) +end+
# File app/controllers/admin/team_members_controller.rb, line 6 +def update + @admin_team_member = UsersProject.find(params[:id]) + + if @admin_team_member.update_attributes(params[:team_member]) + redirect_to [:admin, @admin_team_member.project], notice: 'Project Access was successfully updated.' + else + render action: "edit" + end +end+
AdminController + +
# File app/controllers/admin/users_controller.rb, line 40 +def block + @admin_user = User.find(params[:id]) + + if @admin_user.block + redirect_to :back, alert: "Successfully blocked" + else + redirect_to :back, alert: "Error occured. User was not blocked" + end +end+
# File app/controllers/admin/users_controller.rb, line 60 +def create + admin = params[:user].delete("admin") + + @admin_user = User.new(params[:user], as: :admin) + @admin_user.admin = (admin && admin.to_i > 0) + + respond_to do |format| + if @admin_user.save + format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } + format.json { render json: @admin_user, status: :created, location: @admin_user } + else + format.html { render action: "new" } + format.json { render json: @admin_user.errors, status: :unprocessable_entity } + end + end +end+
# File app/controllers/admin/users_controller.rb, line 99 +def destroy + @admin_user = User.find(params[:id]) + @admin_user.destroy + + respond_to do |format| + format.html { redirect_to admin_users_url } + format.json { head :ok } + end +end+
# File app/controllers/admin/users_controller.rb, line 36 +def edit + @admin_user = User.find(params[:id]) +end+
# File app/controllers/admin/users_controller.rb, line 2 +def index + @admin_users = User.scoped + @admin_users = @admin_users.filter(params[:filter]) + @admin_users = @admin_users.search(params[:name]) if params[:name].present? + @admin_users = @admin_users.order("updated_at DESC").page(params[:page]) +end+
# File app/controllers/admin/users_controller.rb, line 32 +def new + @admin_user = User.new({ projects_limit: Gitlab.config.default_projects_limit }, as: :admin) +end+
# File app/controllers/admin/users_controller.rb, line 9 +def show + @admin_user = User.find(params[:id]) + + @projects = if @admin_user.projects.empty? + Project + else + Project.without_user(@admin_user) + end.all +end+
# File app/controllers/admin/users_controller.rb, line 19 +def team_update + @admin_user = User.find(params[:id]) + + UsersProject.user_bulk_import( + @admin_user, + params[:project_ids], + params[:project_access] + ) + + redirect_to [:admin, @admin_user], notice: 'Teams were successfully updated.' +end+
# File app/controllers/admin/users_controller.rb, line 50 +def unblock + @admin_user = User.find(params[:id]) + + if @admin_user.update_attribute(:blocked, false) + redirect_to :back, alert: "Successfully unblocked" + else + redirect_to :back, alert: "Error occured. User was not unblocked" + end +end+
# File app/controllers/admin/users_controller.rb, line 77 +def update + admin = params[:user].delete("admin") + + if params[:user][:password].blank? + params[:user].delete(:password) + params[:user].delete(:password_confirmation) + end + + @admin_user = User.find(params[:id]) + @admin_user.admin = (admin && admin.to_i > 0) + + respond_to do |format| + if @admin_user.update_attributes(params[:user], as: :admin) + format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully updated.' } + format.json { head :ok } + else + format.html { render action: "edit" } + format.json { render json: @admin_user.errors, status: :unprocessable_entity } + end + end +end+
Provides a base class for Admin controllers to +subclass
+ +Automatically sets the layout and ensures an administrator is logged in
+ +# File app/controllers/admin_controller.rb, line 8 +def authenticate_admin! + return render_404 unless current_user.is_admin? +end+
ActionController::Base + +
# File app/controllers/application_controller.rb, line 48 +def abilities + @abilities ||= Six.new +end+
# File app/controllers/application_controller.rb, line 73 +def access_denied! + render "errors/access_denied", layout: "errors", status: 404 +end+
# File app/controllers/application_controller.rb, line 61 +def add_project_abilities + abilities << Ability +end+
# File app/controllers/application_controller.rb, line 33 +def after_sign_in_path_for resource + if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked + sign_out resource + flash[:alert] = "Your account was blocked" + new_user_session_path + else + super + end +end+
# File app/controllers/application_controller.rb, line 52 +def can?(object, action, subject) + abilities.allowed?(object, action, subject) +end+
# File app/controllers/application_controller.rb, line 107 +def dev_tools + Rack::MiniProfiler.authorize_request +end+
# File app/controllers/application_controller.rb, line 81 +def git_not_found! + render "errors/git_not_found", layout: "errors", status: 404 +end+
# File app/controllers/application_controller.rb, line 85 +def method_missing(method_sym, *arguments, &block) + if method_sym.to_s =~ %r^authorize_(.*)!$/ + authorize_project!($1.to_sym) + else + super + end +end+
# File app/controllers/application_controller.rb, line 101 +def no_cache_headers + response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" + response.headers["Pragma"] = "no-cache" + response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" +end+
# File app/controllers/application_controller.rb, line 77 +def not_found! + render "errors/not_found", layout: "errors", status: 404 +end+
# File app/controllers/application_controller.rb, line 56 +def project + @project ||= current_user.projects.find_by_code(params[:project_id] || params[:id]) + @project || render_404 +end+
# File app/controllers/application_controller.rb, line 25 +def reject_blocked! + if current_user && current_user.blocked + sign_out current_user + flash[:alert] = "Your account was blocked" + redirect_to new_user_session_path + end +end+
# File app/controllers/application_controller.rb, line 93 +def render_404 + render file: Rails.root.join("public", "404"), layout: false, status: "404" +end+
# File app/controllers/application_controller.rb, line 97 +def require_non_empty_project + redirect_to @project if @project.empty_repo? +end+
# File app/controllers/application_controller.rb, line 43 +def set_current_user_for_observers + MergeRequestObserver.current_user = current_user + IssueObserver.current_user = current_user +end+
Draper::Base + +
# File app/helpers/application_helper.rb, line 125 +def app_theme + Gitlab::Theme.css_class_by_id(current_user.try(:theme_id)) +end+
Check if a partcular action is the current one
+ +args - One or more action names to check
+ +Examples
+ +# On Projects#new +current_action?(:new) # => true +current_action?(:create) # => false +current_action?(:new, :create) # => true ++ + + +
# File app/helpers/application_helper.rb, line 29 +def current_action?(*args) + args.any? { |v| v.to_s.downcase == action_name } +end+
Check if a particular controller is the current one
+ +args - One or more controller names to check
+ +Examples
+ +# On TreeController +current_controller?(:tree) # => true +current_controller?(:commits) # => false +current_controller?(:commits, :tree) # => true ++ + + +
# File app/helpers/application_helper.rb, line 15 +def current_controller?(*args) + args.any? { |v| v.to_s.downcase == controller.controller_name } +end+
# File app/helpers/application_helper.rb, line 115 +def emoji_autocomplete_source + # should be an array of strings + # so to_s can be called, because it is sufficient and to_json is too slow + Emoji.names.to_s +end+
# File app/helpers/application_helper.rb, line 33 +def gravatar_icon(user_email = '', size = 40) + if Gitlab.config.disable_gravatar? || user_email.blank? + 'no_avatar.png' + else + gravatar_prefix = request.ssl? ? "https://secure" : "http://www" + user_email.strip! + "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" + end +end+
# File app/helpers/application_helper.rb, line 61 +def grouped_options_refs(destination = :tree) + options = [ + ["Branch", @project.branch_names ], + [ "Tag", @project.tag_names ] + ] + + # If reference is commit id - + # we should add it to branch/tag selectbox + if(@ref && !options.flatten.include?(@ref) && + @ref =~ %r^[0-9a-zA-Z]{6,52}$/) + options << ["Commit", [@ref]] + end + + grouped_options_for_select(options, @ref || @project.default_branch) +end+
# File app/helpers/application_helper.rb, line 137 +def hexdigest(string) + Digest::SHA1.hexdigest string +end+
# File app/helpers/application_helper.rb, line 51 +def last_commit(project) + if project.repo_exists? + time_ago_in_words(project.commit.committed_date) + " ago" + else + "Never" + end +rescue + "Never" +end+
# File app/helpers/application_helper.rb, line 121 +def ldap_enable? + Devise.omniauth_providers.include?(:ldap) +end+
# File app/helpers/application_helper.rb, line 141 +def project_last_activity project + activity = project.last_activity + if activity && activity.created_at + time_ago_in_words(activity.created_at) + " ago" + else + "Never" + end +end+
# File app/helpers/application_helper.rb, line 43 +def request_protocol + request.ssl? ? "https" : "http" +end+
# File app/helpers/application_helper.rb, line 77 +def search_autocomplete_source + projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } } + + default_nav = [ + { label: "My Profile", url: profile_path }, + { label: "My SSH Keys", url: keys_path }, + { label: "My Dashboard", url: root_path }, + { label: "Admin Section", url: admin_root_path }, + ] + + help_nav = [ + { label: "Workflow Help", url: help_workflow_path }, + { label: "Permissions Help", url: help_permissions_path }, + { label: "Web Hooks Help", url: help_web_hooks_path }, + { label: "System Hooks Help", url: help_system_hooks_path }, + { label: "API Help", url: help_api_path }, + { label: "Markdown Help", url: help_markdown_path }, + { label: "SSH Keys Help", url: help_ssh_path }, + ] + + project_nav = [] + if @project && !@project.new_record? + project_nav = [ + { label: "#{@project.name} Issues", url: project_issues_path(@project) }, + { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) }, + { label: "#{@project.name} Milestones", url: project_milestones_path(@project) }, + { label: "#{@project.name} Snippets", url: project_snippets_path(@project) }, + { label: "#{@project.name} Team", url: project_team_index_path(@project) }, + { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Wall", url: wall_project_path(@project) }, + { label: "#{@project.name} Wiki", url: project_wikis_path(@project) }, + ] + end + + [projects, default_nav, project_nav, help_nav].flatten.to_json +end+
# File app/helpers/application_helper.rb, line 129 +def show_last_push_widget?(event) + event && + event.last_push_to_non_root? && + !event.rm_ref? && + event.project && + event.project.merge_requests_enabled +end+
# File app/helpers/application_helper.rb, line 47 +def web_app_url + "#{request_protocol}://#{Gitlab.config.web_host}/" +end+
CarrierWave::Uploader::Base + +
Override the directory where uploaded files will be stored. This is a +sensible default for uploaders that are meant to be mounted:
+ + + +# File app/uploaders/attachment_uploader.rb, line 15 +def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" +end+
Compatible with all access rights Should be rewrited for new access rights
+ + + +# File app/roles/authority.rb, line 4 +def add_access(user, *access) + access = if access.include?(:admin) + { project_access: UsersProject::MASTER } + elsif access.include?(:write) + { project_access: UsersProject::DEVELOPER } + else + { project_access: UsersProject::REPORTER } + end + opts = { user: user } + opts.merge!(access) + users_projects.create(opts) +end+
# File app/roles/authority.rb, line 39 +def allow_read_for?(user) + !users_projects.where(user_id: user.id).empty? +end+
# File app/roles/authority.rb, line 51 +def dev_access_for?(user) + !users_projects.where(user_id: user.id, project_access: [UsersProject::DEVELOPER, UsersProject::MASTER]).empty? +end+
# File app/roles/authority.rb, line 43 +def guest_access_for?(user) + !users_projects.where(user_id: user.id).empty? +end+
# File app/roles/authority.rb, line 55 +def master_access_for?(user) + !users_projects.where(user_id: user.id, project_access: [UsersProject::MASTER]).empty? +end+
# File app/roles/authority.rb, line 47 +def report_access_for?(user) + !users_projects.where(user_id: user.id, project_access: [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty? +end+
# File app/roles/authority.rb, line 33 +def repository_masters + keys = Key.joins({user: :users_projects}). + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER) + keys.map(&:identifier) +end+
# File app/roles/authority.rb, line 21 +def repository_readers + keys = Key.joins({user: :users_projects}). + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER) + keys.map(&:identifier) + deploy_keys.map(&:identifier) +end+
# File app/roles/authority.rb, line 27 +def repository_writers + keys = Key.joins({user: :users_projects}). + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER) + keys.map(&:identifier) +end+
# File app/roles/authority.rb, line 17 +def reset_access(user) + users_projects.where(project_id: self.id, user_id: user.id).destroy if self.id +end+
Object + +
# File app/contexts/base_context.rb, line 4 +def initialize(project, user, params) + @project, @current_user, @params = project, user, params.dup +end+
# File app/contexts/base_context.rb, line 8 +def abilities + @abilities ||= begin + abilities = Six.new + abilities << Ability + abilities + end +end+
# File app/contexts/base_context.rb, line 16 +def can?(object, action, subject) + abilities.allowed?(object, action, subject) +end+
Controller for viewing a file’s blame
+ +# File app/controllers/blame_controller.rb, line 12 +def show + @repo = @project.repo + @blame = Grit::Blob.blame(@repo, @commit.id, @path) +end+
Controller for viewing a file’s blame
+ +# File app/controllers/blob_controller.rb, line 13 +def show + if @tree.is_blob? + if @tree.text? + encoding = detect_encoding(@tree.data) + mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain" + else + mime_type = @tree.mime_type + end + + send_data( + @tree.data, + type: mime_type, + disposition: 'inline', + filename: @tree.name + ) + else + not_found! + end +end+
Object + +
# File app/models/commit.rb, line 58 +def commits(repo, ref, path = nil, limit = nil, offset = nil) + if path + repo.log(ref, path, max_count: limit, skip: offset) + elsif limit && offset + repo.commits(ref, limit, offset) + else + repo.commits(ref) + end.map{ |c| Commit.new(c) } +end+
# File app/models/commit.rb, line 68 +def commits_between(repo, from, to) + repo.commits_between(from, to).map { |c| Commit.new(c) } +end+
# File app/models/commit.rb, line 46 +def commits_since(repo, date) + commits = repo.heads.map do |h| + repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } + end.flatten.uniq { |c| c.id } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits +end+
# File app/models/commit.rb, line 36 +def commits_with_refs(repo, n = 20) + commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits[0..n] +end+
# File app/models/commit.rb, line 72 +def compare(project, from, to) + result = { + commits: [], + diffs: [], + commit: nil, + same: false + } + + return result unless from && to + + first = project.commit(to.try(:strip)) + last = project.commit(from.try(:strip)) + + if first && last + commits = [first, last].sort_by(&:created_at) + younger = commits.first + older = commits.last + + result[:same] = (younger.id == older.id) + result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} + result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] + result[:commit] = Commit.new(older) + end + + result +end+
# File app/models/commit.rb, line 14 +def find_or_first(repo, commit_id = nil, root_ref) + commit = if commit_id + repo.commit(commit_id) + else + repo.commits(root_ref).first + end + + Commit.new(commit) if commit +end+
# File app/models/commit.rb, line 24 +def fresh_commits(repo, n = 10) + commits = repo.heads.map do |h| + repo.commits(h.name, n).map { |c| Commit.new(c, h) } + end.flatten.uniq { |c| c.id } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits[0...n] +end+
# File app/models/commit.rb, line 100 +def initialize(raw_commit, head = nil) + @commit = raw_commit + @head = head +end+
# File app/models/commit.rb, line 134 +def committer_email + committer.email +end+
# File app/models/commit.rb, line 130 +def committer_name + utf8 committer.name +end+
# File app/models/commit.rb, line 113 +def created_at + committed_date +end+
Was this commit committed by a different person than the original author?
+ + + +# File app/models/commit.rb, line 126 +def different_committer? + author_name != committer_name || author_email != committer_email +end+
# File app/models/commit.rb, line 146 +def parents_count + parents && parents.count || 0 +end+
# File app/models/commit.rb, line 138 +def prev_commit + parents.try :first +end+
# File app/models/commit.rb, line 142 +def prev_commit_id + prev_commit.try :id +end+
# File app/models/commit.rb, line 109 +def safe_message + @safe_message ||= utf8 message +end+
# File app/models/commit.rb, line 105 +def short_id(length = 10) + id.to_s[0..length] +end+
Controller for a specific Commit
+ +Not to be confused with CommitsController, plural.
+ +# File app/controllers/commit_controller.rb, line 10 +def show + result = CommitLoadContext.new(project, current_user, params).execute + + @commit = result[:commit] + git_not_found! unless @commit + + @suppress_diff = result[:suppress_diff] + @note = result[:note] + @line_notes = result[:line_notes] + @notes_count = result[:notes_count] + @comments_allowed = true + + respond_to do |format| + format.html do + if result[:status] == :huge_commit + render "huge_commit" and return + end + end + + format.patch + end +end+
Returns the commits description
+ +cut off, ellipses (`&hellp;`) are prepended to the commit message.
+ + + +# File app/decorators/commit_decorator.rb, line 34 +def description + description = safe_message + + title_end = description.index(%r\n/) + if (!title_end && description.length > 80) || (title_end && title_end > 80) + "…".html_safe << description[70..-1] + else + description.split(%r\n/, 2)[1].try(:chomp) + end +end+
Returns a string describing the commit for use in a link title
+ +Example
+ +"Commit: Alex Denisov - Project git clone panel"+ + + +
# File app/decorators/commit_decorator.rb, line 9 +def link_title + "Commit: #{author_name} - #{title}" +end+
Returns the commits title.
+ +Usually, the commit title is the first line of the commit message. In case +this first line is longer than 80 characters, it is cut off after 70 +characters and ellipses (`&hellp;`) are appended.
+ + + +# File app/decorators/commit_decorator.rb, line 18 +def title + title = safe_message + + return no_commit_message if title.blank? + + title_end = title.index(%r\n/) + if (!title_end && title.length > 80) || (title_end && title_end > 80) + title[0..69] << "…".html_safe + else + title.split(%r\n/, 2).first + end +end+
# File app/decorators/commit_decorator.rb, line 69 +def no_commit_message + "--no commit message" +end+
BaseContext + +
# File app/contexts/commit_load_context.rb, line 2 +def execute + result = { + commit: nil, + suppress_diff: false, + line_notes: [], + notes_count: 0, + note: nil, + status: :ok + } + + commit = project.commit(params[:id]) + + if commit + commit = CommitDecorator.decorate(commit) + line_notes = project.commit_line_notes(commit) + + result[:commit] = commit + result[:note] = project.build_commit_note(commit) + result[:line_notes] = line_notes + result[:notes_count] = line_notes.count + project.commit_notes(commit).count + + begin + result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff] + rescue Grit::Git::GitTimeout + result[:suppress_diff] = true + result[:status] = :huge_commit + end + end + + result +end+
# File app/controllers/commits_controller.rb, line 11 +def show + @repo = @project.repo + @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) + + @commits = @project.commits(@ref, @path, @limit, @offset) + @commits = CommitDecorator.decorate(@commits) + + respond_to do |format| + format.html # index.html.erb + format.js + format.atom { render layout: false } + end +end+
# File app/helpers/commits_helper.rb, line 12 +def build_line_anchor(index, line_new, line_old) + "#{index}_#{line_old}_#{line_new}" +end+
# File app/helpers/commits_helper.rb, line 16 +def each_diff_line(diff_arr, index) + line_old = 1 + line_new = 1 + type = nil + + lines_arr = ::Gitlab::InlineDiff.processing diff_arr + lines_arr.each do |line| + next if line.match(%r^\-\-\- \/dev\/null/) + next if line.match(%r^\+\+\+ \/dev\/null/) + next if line.match(%r^\-\-\- a/) + next if line.match(%r^\+\+\+ b/) + + full_line = html_escape(line.gsub(%r\n/, '')) + full_line = ::Gitlab::InlineDiff.replace_markers full_line + + if line.match(%r^@@ -/) + type = "match" + + line_old = line.match(%r\-[0-9]*/)[0].to_i.abs rescue 0 + line_new = line.match(%r\+[0-9]*/)[0].to_i.abs rescue 0 + + next if line_old == 1 && line_new == 1 #top of file + yield(full_line, type, nil, nil, nil) + next + else + type = identification_type(line) + line_code = build_line_anchor(index, line_new, line_old) + yield(full_line, type, line_code, line_new, line_old) + end + + + if line[0] == "+" + line_new += 1 + elsif line[0] == "-" + line_old += 1 + else + line_new += 1 + line_old += 1 + end + end +end+
# File app/helpers/commits_helper.rb, line 2 +def identification_type(line) + if line[0] == "+" + "new" + elsif line[0] == "-" + "old" + else + nil + end +end+
# File app/helpers/commits_helper.rb, line 58 +def image_diff_class(diff) + if diff.deleted_file + "diff_image_removed" + elsif diff.new_file + "diff_image_added" + else + nil + end +end+
# File app/controllers/compare_controller.rb, line 22 +def create + redirect_to project_compare_path(@project, params[:from], params[:to]) +end+
# File app/controllers/compare_controller.rb, line 7 +def index +end+
# File app/controllers/compare_controller.rb, line 10 +def show + result = Commit.compare(project, params[:from], params[:to]) + + @commits = result[:commits] + @commit = result[:commit] + @diffs = result[:diffs] + @refs_are_same = result[:same] + @line_notes = [] + + @commits = CommitDecorator.decorate(@commits) +end+
# File app/controllers/dashboard_controller.rb, line 4 +def index + @groups = Group.where(id: current_user.projects.pluck(:group_id)) + @projects = current_user.projects_with_events + @projects = @projects.page(params[:page]).per(30) + + @events = Event.in_projects(current_user.project_ids).limit(20).offset(params[:offset] || 0) + @last_push = current_user.recent_push + + respond_to do |format| + format.html + format.js + format.atom { render layout: false } + end +end+
Get only assigned issues
+ + + +# File app/controllers/dashboard_controller.rb, line 26 +def issues + @projects = current_user.projects.all + @user = current_user + @issues = current_user.assigned_issues.opened.recent.page(params[:page]).per(20) + @issues = @issues.includes(:author, :project) + + respond_to do |format| + format.html + format.atom { render layout: false } + end +end+
Get authored or assigned open merge requests
+ + + +# File app/controllers/dashboard_controller.rb, line 20 +def merge_requests + @projects = current_user.projects.all + @merge_requests = current_user.cared_merge_requests.recent.page(params[:page]).per(20) +end+
# File app/controllers/deploy_keys_controller.rb, line 21 +def create + @key = @project.deploy_keys.new(params[:key]) + if @key.save + redirect_to project_deploy_keys_path(@project) + else + render "new" + end +end+
# File app/controllers/deploy_keys_controller.rb, line 30 +def destroy + @key = @project.deploy_keys.find(params[:id]) + @key.destroy + + respond_to do |format| + format.html { redirect_to project_deploy_keys_url } + format.js { render nothing: true } + end +end+
# File app/controllers/deploy_keys_controller.rb, line 7 +def index + @keys = @project.deploy_keys.all +end+
# File app/controllers/deploy_keys_controller.rb, line 15 +def new + @key = @project.deploy_keys.new + + respond_with(@key) +end+
# File app/controllers/deploy_keys_controller.rb, line 11 +def show + @key = @project.deploy_keys.find(params[:id]) +end+
# File app/controllers/errors_controller.rb, line 2 +def githost + render "errors/gitolite" +end+
ActiveRecord::Base + +
# File app/models/event.rb, line 36 +def determine_action(record) + if [Issue, MergeRequest].include? record.class + Event::Created + elsif record.kind_of? Note + Event::Commented + end +end+
# File app/models/event.rb, line 133 +def action_name + if closed? + "closed" + elsif merged? + "merged" + elsif joined? + 'joined' + elsif left? + 'left' + else + "opened" + end +end+
Next events currently enabled for system
+ +- push +- new issue +- merge request+ + + +
# File app/models/event.rb, line 49 +def allowed? + push? || issue? || merge_request? || membership_changed? +end+
# File app/models/event.rb, line 104 +def changed_issue? + target_type == "Issue" && + [Closed, Reopened].include?(action) +end+
# File app/models/event.rb, line 99 +def changed_merge_request? + target_type == "MergeRequest" && + [Closed, Reopened].include?(action) +end+
# File app/models/event.rb, line 73 +def closed? + action == self.class::Closed +end+
# File app/models/event.rb, line 121 +def issue + target if target_type == "Issue" +end+
# File app/models/event.rb, line 81 +def issue? + target_type == "Issue" +end+
# File app/models/event.rb, line 109 +def joined? + action == Joined +end+
# File app/models/event.rb, line 113 +def left? + action == Left +end+
# File app/models/event.rb, line 117 +def membership_changed? + joined? || left? +end+
# File app/models/event.rb, line 125 +def merge_request + target if target_type == "MergeRequest" +end+
# File app/models/event.rb, line 85 +def merge_request? + target_type == "MergeRequest" +end+
# File app/models/event.rb, line 69 +def merged? + action == self.class::Merged +end+
# File app/models/event.rb, line 89 +def new_issue? + target_type == "Issue" && + action == Created +end+
# File app/models/event.rb, line 94 +def new_merge_request? + target_type == "MergeRequest" && + action == Created +end+
# File app/models/event.rb, line 53 +def project_name + if project + project.name + else + "(deleted project)" + end +end+
# File app/models/event.rb, line 65 +def push? + action == self.class::Pushed && valid_push? +end+
# File app/models/event.rb, line 77 +def reopened? + action == self.class::Reopened +end+
# File app/models/event.rb, line 61 +def target_title + target.try :title +end+
# File app/decorators/event_decorator.rb, line 37 +def feed_summary + if self.issue? + h.render "events/event_issue", issue: self.issue + elsif self.push? + h.render "events/event_push", event: self + end +end+
# File app/decorators/event_decorator.rb, line 4 +def feed_title + if self.issue? + "#{self.author_name} #{self.action_name} issue ##{self.target_id}: #{self.issue_title} at #{self.project.name}" + elsif self.merge_request? + "#{self.author_name} #{self.action_name} MR ##{self.target_id}: #{self.merge_request_title} at #{self.project.name}" + elsif self.push? + "#{self.author_name} #{self.push_action_name} #{self.ref_type} #{self.ref_name} at #{self.project.name}" + elsif self.membership_changed? + "#{self.author_name} #{self.action_name} #{self.project.name}" + else + "" + end +end+
# File app/decorators/event_decorator.rb, line 18 +def feed_url + if self.issue? + h.project_issue_url(self.project, self.issue) + elsif self.merge_request? + h.project_merge_request_url(self.project, self.merge_request) + + elsif self.push? + if self.push_with_commits? + if self.commits_count > 1 + h.project_compare_url(self.project, :from => self.parent_commit.id, :to => self.last_commit.id) + else + h.project_commit_url(self.project, :id => self.last_commit.id) + end + else + h.project_commits_url(self.project, self.ref_name) + end + end +end+
# File app/helpers/events_helper.rb, line 13 +def event_action_name(event) + target = if event.target_type + event.target_type.titleize.downcase + else + 'project' + end + + [event.action_name, target].join(" ") +end+
# File app/helpers/events_helper.rb, line 23 +def event_image event + event_image_path = if event.push? + "event_push.png" + elsif event.merged? + "event_mr_merged.png" + end + + return nil unless event_image_path + + content_tag :div, class: 'event_icon' do + image_tag event_image_path + end +end+
Module providing methods for dealing with separating a tree-ish string and +a file path string when combined in a request parameter
+ +Assigns common instance variables for views working with Git tree-ish +objects
+ +Assignments are:
+@id - A string representing the joined ref and path
+@ref - A string representing the ref (e.g., the branch, tag, or commit +SHA)
+@path - A string representing the filesystem path
+@commit - A CommitDecorator representing +the commit from the given ref
+@tree - A TreeDecorator representing the +tree at the given ref/path
+If the :id parameter appears to be requesting a specific response format, +that will be handled as well.
+ +Automatically renders `not_found!` if a valid tree path could not be +resolved (e.g., when a user inserts an invalid path or ref).
+ + + +# File lib/extracts_path.rb, line 94 +def assign_ref_vars + # Handle formats embedded in the id + if params[:id].ends_with?('.atom') + params[:id].gsub!(%r\.atom$/, '') + request.format = :atom + end + + @ref, @path = extract_ref(params[:id]) + + @id = File.join(@ref, @path) + + @commit = CommitDecorator.decorate(@project.commit(@ref)) + + @tree = Tree.new(@commit.tree, @project, @ref, @path) + @tree = TreeDecorator.new(@tree) + + raise InvalidPathError if @tree.invalid? +rescue NoMethodError, InvalidPathError + not_found! +end+
Given a string containing both a Git tree-ish, such as a branch or tag, and +a filesystem path joined by forward slashes, attempts to separate the two.
+ +Expects a @project instance variable to contain the active project. This is +used to check the input against a list of valid repository refs.
+ +Examples
+ +# No @project available +extract_ref('master') +# => ['', ''] + +extract_ref('master') +# => ['master', ''] + +extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG") +# => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG'] + +extract_ref("v2.0.0/README.md") +# => ['v2.0.0', 'README.md'] + +extract_ref('issues/1234/app/models/project.rb') +# => ['issues/1234', 'app/models/project.rb'] + +# Given an invalid branch, we fall back to just splitting on the first slash +extract_ref('non/existent/branch/README.md') +# => ['non', 'existent/branch/README.md'] ++ +
Returns an Array where the first value is the tree-ish and the second is +the path
+ + + +# File lib/extracts_path.rb, line 45 +def extract_ref(input) + pair = ['', ''] + + return pair unless @project + + if input.match(%r^([[:alnum:]]{40})(.+)/) + # If the ref appears to be a SHA, we're done, just split the string + pair = $~.captures + else + # Otherwise, attempt to detect the ref using a list of the project's + # branches and tags + + # Append a trailing slash if we only get a ref and no file path + id = input + id += '/' unless id.ends_with?('/') + + valid_refs = @project.ref_names + valid_refs.select! { |v| id.start_with?("#{v}/") } + + if valid_refs.length != 1 + # No exact ref match, so just try our best + pair = id.match(%r([^\/]+)(.*)/).captures + else + # Partition the string into the ref and the path, ignoring the empty first value + pair = id.partition(valid_refs.first)[1..-1] + end + end + + # Remove ending slashes from path + pair[1].gsub!(%r^\/|\/$/, '') + + pair +end+
StandardError + +
Raised when given an invalid file path
+ +ActiveModel::EachValidator + +
# File lib/file_size_validator.rb, line 8 +def initialize(options) + if range = (options.delete(:in) || options.delete(:within)) + raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range) + options[:minimum], options[:maximum] = range.begin, range.end + options[:maximum] -= 1 if range.exclude_end? + end + + super +end+
# File lib/file_size_validator.rb, line 18 +def check_validity! + keys = CHECKS.keys & options.keys + + if keys.empty? + raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.' + end + + keys.each do |key| + value = options[key] + + unless value.is_a?(Integer) && value >= 0 + raise ArgumentError, ":#{key} must be a nonnegative Integer" + end + end +end+
# File lib/file_size_validator.rb, line 57 +def help + Helper.instance +end+
# File lib/file_size_validator.rb, line 34 +def validate_each(record, attribute, value) + raise(ArgumentError, "A CarrierWave::Uploader::Base object was expected") unless value.kind_of? CarrierWave::Uploader::Base + + value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String) + + CHECKS.each do |key, validity_check| + next unless check_value = options[key] + + value ||= [] if key == :maximum + + value_size = value.size + next if value_size.send(validity_check, check_value) + + errors_options = options.except(*RESERVED_OPTIONS) + errors_options[:file_size] = help.number_to_human_size check_value + + default_message = options[MESSAGES[key]] + errors_options[:message] ||= default_message if default_message + + record.errors.add(attribute, MESSAGES[key], errors_options) + end +end+
Object + +
# File app/roles/git_host.rb, line 2 +def git_host + Gitlab::Gitolite.new +end+
Grape::API + +
# File lib/api/helpers.rb, line 35 +def attributes_for_keys(keys) + attrs = {} + keys.each do |key| + attrs[key] = params[key] if params[key].present? + end + attrs +end+
# File lib/api/helpers.rb, line 21 +def authenticate! + unauthorized! unless current_user +end+
# File lib/api/helpers.rb, line 25 +def authenticated_as_admin! + forbidden! unless current_user.is_admin? +end+
# File lib/api/helpers.rb, line 3 +def current_user + @current_user ||= User.find_by_authentication_token(params[:private_token] || env["HTTP_PRIVATE_TOKEN"]) +end+
error helpers
+ + + +# File lib/api/helpers.rb, line 45 +def forbidden! + render_api_error!('403 Forbidden', 403) +end+
# File lib/api/helpers.rb, line 60 +def not_allowed! + render_api_error!('Method Not Allowed', 405) +end+
# File lib/api/helpers.rb, line 49 +def not_found!(resource = nil) + message = ["404"] + message << resource if resource + message << "Not Found" + render_api_error!(message.join(' '), 404) +end+
# File lib/api/helpers.rb, line 17 +def paginate(object) + object.page(params[:page]).per(params[:per_page].to_i) +end+
# File lib/api/helpers.rb, line 64 +def render_api_error!(message, status) + error!({'message' => message}, status) +end+
# File lib/api/helpers.rb, line 7 +def user_project + if @project ||= current_user.projects.find_by_id(params[:id]) || + current_user.projects.find_by_code(params[:id]) + else + not_found! + end + + @project +end+
Gitlab::Logger + +
# File lib/gitlab/app_logger.rb, line 3 +def self.file_name + 'application.log' +end+
# File lib/gitlab/app_logger.rb, line 7 +def format_message(severity, timestamp, progname, msg) + "#{timestamp.to_s(:long)}: #{msg}\n" +end+
Object + +
# File lib/gitlab/auth.rb, line 20 +def create_from_omniauth(auth, ldap = false) + provider = auth.provider + uid = auth.info.uid || auth.uid + name = auth.info.name.force_encoding("utf-8") + email = auth.info.email.downcase unless auth.info.email.nil? + + ldap_prefix = ldap ? '(LDAP) ' : '' + raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email" " address" if auth.info.email.blank? + + log.info "#{ldap_prefix}Creating user from #{provider} login" " {uid => #{uid}, name => #{name}, email => #{email}}" + password = Devise.friendly_token[0, 8].downcase + @user = User.new({ + extern_uid: uid, + provider: provider, + name: name, + email: email, + password: password, + password_confirmation: password, + projects_limit: Gitlab.config.default_projects_limit, + }, as: :admin) + if Gitlab.config.omniauth['block_auto_created_users'] && !ldap + @user.blocked = true + end + @user.save! + @user +end+
# File lib/gitlab/auth.rb, line 3 +def find_for_ldap_auth(auth, signed_in_resource = nil) + uid = auth.info.uid + provider = auth.provider + email = auth.info.email.downcase unless auth.info.email.nil? + raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil? + + if @user = User.find_by_extern_uid_and_provider(uid, provider) + @user + elsif @user = User.find_by_email(email) + log.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}" + @user.update_attributes(:extern_uid => uid, :provider => provider) + @user + else + create_from_omniauth(auth, true) + end +end+
# File lib/gitlab/auth.rb, line 49 +def find_or_new_for_omniauth(auth) + provider, uid = auth.provider, auth.uid + email = auth.info.email.downcase unless auth.info.email.nil? + + if @user = User.find_by_provider_and_extern_uid(provider, uid) + @user + elsif @user = User.find_by_email(email) + @user.update_attributes(:extern_uid => uid, :provider => provider) + @user + else + if Gitlab.config.omniauth['allow_single_sign_on'] + @user = create_from_omniauth(auth) + @user + end + end +end+
# File lib/gitlab/auth.rb, line 66 +def log + Gitlab::AppLogger +end+
# File lib/gitlab/encode.rb, line 34 +def detect_encoding message + return nil unless message + + hash = CharlockHolmes::EncodingDetector.detect(message) rescue {} + return hash[:encoding] ? hash[:encoding] : nil +end+
# File lib/gitlab/encode.rb, line 7 +def utf8 message + # return nil if message is nil + return nil unless message + + message.force_encoding("utf-8") + # return message if message type is binary + detect = CharlockHolmes::EncodingDetector.detect(message) + return message if detect[:type] == :binary + + # if message is utf-8 encoding, just return it + return message if message.valid_encoding? + + # if message is not utf-8 encoding, convert it + if detect[:encoding] + message.force_encoding(detect[:encoding]) + message.encode!("utf-8", detect[:encoding], undef: :replace, replace: "", invalid: :replace) + end + + # ensure message encoding is utf8 + message.valid_encoding? ? message : raise + +# Prevent app from crash cause of encoding errors +rescue + encoding = detect ? detect[:encoding] : "unknown" + "--broken encoding: #{encoding}" +end+
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Grape::Entity + +
Object + +
GitLab file editor
+ +It gives you ability to make changes to files & commit this changes +from GitLab UI.
+ +# File lib/gitlab/file_editor.rb, line 9 +def initialize(user, project, ref) + self.user = user + self.project = project + self.ref = ref +end+
# File lib/gitlab/file_editor.rb, line 15 +def update(path, content, commit_message, last_commit) + return false unless can_edit?(path, last_commit) + + Grit::Git.with_timeout(10.seconds) do + lock_file = Rails.root.join("tmp", "#{project.path}.lock") + + File.open(lock_file, "w+") do |f| + f.flock(File::LOCK_EX) + + unless project.satellite.exists? + raise "Satellite doesn't exist" + end + + project.satellite.clear + + Dir.chdir(project.satellite.path) do + r = Grit::Repo.new('.') + r.git.sh "git reset --hard" + r.git.sh "git fetch origin" + r.git.sh "git config user.name \"#{user.name}\"" + r.git.sh "git config user.email \"#{user.email}\"" + r.git.sh "git checkout -b #{ref} origin/#{ref}" + File.open(path, 'w'){|f| f.write(content)} + r.git.sh "git add ." + r.git.sh "git commit -am '#{commit_message}'" + output = r.git.sh "git push origin #{ref}" + + if output =~ %rreject/ + return false + end + end + end + end + true +end+
# File lib/gitlab/file_editor.rb, line 53 +def can_edit?(path, last_commit) + current_last_commit = @project.last_commit_for(ref, path).sha + last_commit == current_last_commit +end+
Gitlab::Logger + +
# File lib/gitlab/git_logger.rb, line 3 +def self.file_name + 'githost.log' +end+
# File lib/gitlab/git_logger.rb, line 7 +def format_message(severity, timestamp, progname, msg) + "#{timestamp.to_s(:long)} -> #{severity} -> #{msg}\n" +end+
Object + +
# File lib/gitlab/backend/gitolite.rb, line 7 +def config + Gitlab::GitoliteConfig.new +end+
# File lib/gitlab/backend/gitolite.rb, line 37 +def enable_automerge + config.admin_all_repo! +end+
# File lib/gitlab/backend/gitolite.rb, line 18 +def remove_key key_id, projects + config.apply do |config| + config.rm_key(key_id) + config.update_projects(projects) + end +end+
# File lib/gitlab/backend/gitolite.rb, line 29 +def remove_repository project + config.destroy_project!(project) +end+
# File lib/gitlab/backend/gitolite.rb, line 11 +def set_key key_id, key_content, projects + config.apply do |config| + config.write_key(key_id, key_content) + config.update_projects(projects) + end +end+
# File lib/gitlab/backend/gitolite.rb, line 25 +def update_repository project + config.update_project!(project.path, project) +end+
# File lib/gitlab/backend/gitolite.rb, line 33 +def url_to_repo path + Gitlab.config.ssh_path + "#{path}.git" +end+
StandardError + +
Object + +
Enable access to all repos for gitolite admin. We use it for accept merge +request feature
+ + + +# File lib/gitlab/backend/gitolite_config.rb, line 162 +def admin_all_repo + owner_name = Gitlab.config.gitolite_admin_key + + # @ALL repos premission for gitolite owner + repo_name = "@all" + repo = if conf.has_repo?(repo_name) + conf.get_repo(repo_name) + else + ::Gitolite::Config::Repo.new(repo_name) + end + + repo.add_permission("RW+", "", owner_name) + conf.add_repo(repo, true) +end+
# File lib/gitlab/backend/gitolite_config.rb, line 177 +def admin_all_repo! + apply { |config| config.admin_all_repo } +end+
# File lib/gitlab/backend/gitolite_config.rb, line 20 +def apply + Timeout::timeout(30) do + File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f| + begin + # Set exclusive lock + # to prevent race condition + f.flock(File::LOCK_EX) + + # Pull gitolite-admin repo + # in tmp dir before do any changes + pull(config_tmp_dir) + + # Build ga_repo object and @conf + # to access gitolite-admin configuration + @conf = ga_repo.config + + # Do any changes + # in gitolite-admin + # config here + yield(self) + + # Save changes in + # gitolite-admin repo + # before push it + ga_repo.save + + # Push gitolite-admin repo + # to apply all changes + push(config_tmp_dir) + ensure + # Remove tmp dir + # removing the gitolite folder first is important to avoid + # NFS issues. + FileUtils.rm_rf(File.join(config_tmp_dir, 'gitolite')) + + # Remove parent tmp dir + FileUtils.rm_rf(config_tmp_dir) + + # Unlock so other task can access + # gitolite configuration + f.flock(File::LOCK_UN) + end + end + end +rescue PullError => ex + log("Pull error -> " + ex.message) + raise Gitolite::AccessDenied, ex.message + +rescue PushError => ex + log("Push error -> " + " " + ex.message) + raise Gitolite::AccessDenied, ex.message + +rescue Exception => ex + log(ex.class.name + " " + ex.message) + raise Gitolite::AccessDenied.new("gitolite timeout") +end+
# File lib/gitlab/backend/gitolite_config.rb, line 81 +def destroy_project(project) + FileUtils.rm_rf(project.path_to_repo) + conf.rm_repo(project.path) +end+
# File lib/gitlab/backend/gitolite_config.rb, line 86 +def destroy_project!(project) + apply do |config| + config.destroy_project(project) + end +end+
# File lib/gitlab/backend/gitolite_config.rb, line 77 +def log message + Gitlab::GitLogger.error(message) +end+
# File lib/gitlab/backend/gitolite_config.rb, line 98 +def rm_key(user) + key_path = File.join(config_tmp_dir, 'gitolite/keydir', "#{user}.pub") + ga_key = ::Gitolite::SSHKey.from_file(key_path) + ga_repo.rm_key(ga_key) +end+
update or create
+ + + +# File lib/gitlab/backend/gitolite_config.rb, line 105 +def update_project(repo_name, project) + repo = update_project_config(project, conf) + conf.add_repo(repo, true) +end+
# File lib/gitlab/backend/gitolite_config.rb, line 110 +def update_project!(repo_name, project) + apply do |config| + config.update_project(repo_name, project) + end +end+
# File lib/gitlab/backend/gitolite_config.rb, line 125 +def update_project_config(project, conf) + repo_name = project.path + + repo = if conf.has_repo?(repo_name) + conf.get_repo(repo_name) + else + ::Gitolite::Config::Repo.new(repo_name) + end + + name_readers = project.repository_readers + name_writers = project.repository_writers + name_masters = project.repository_masters + + pr_br = project.protected_branches.map(&:name).join("$ ") + + repo.clean_permissions + + # Deny access to protected branches for writers + unless name_writers.blank? || pr_br.blank? + repo.add_permission("-", pr_br.strip + "$ ", name_writers) + end + + # Add read permissions + repo.add_permission("R", "", name_readers) unless name_readers.blank? + + # Add write permissions + repo.add_permission("RW+", "", name_writers) unless name_writers.blank? + repo.add_permission("RW+", "", name_masters) unless name_masters.blank? + + # Add sharedRepository config + repo.set_git_config("core.sharedRepository", "0660") + + repo +end+
Updates many projects and uses project.path as the repo path An order of +magnitude faster than #update_project
+ + + +# File lib/gitlab/backend/gitolite_config.rb, line 118 +def update_projects(projects) + projects.each do |project| + repo = update_project_config(project, conf) + conf.add_repo(repo, true) + end +end+
# File lib/gitlab/backend/gitolite_config.rb, line 92 +def write_key(id, key) + File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f| + f.write(key.gsub(%r\n/,'')) + end +end+
StandardError + +
StandardError + +
Object + +
# File lib/gitlab/graph_commit.rb, line 113 +def self.find_free_space(time_range) + reserved = [] + for day in time_range + reserved += @_reserved[day] + end + space = 1 + while reserved.include? space do + space += 1 + end + space +end+
Method is adding time and space on the list of commits. As well as returns +date list corelated with time set on commits.
+ +@param [Array<GraphCommit>] comits to index
+ +@return [Array<TimeDate>] list of commit dates corelated with time on +commits
+ + + +# File lib/gitlab/graph_commit.rb, line 33 +def self.index_commits(commits) + days, heads = [], [] + map = {} + + commits.reverse.each_with_index do |c,i| + c.time = i + days[i] = c.committed_date + map[c.id] = c + heads += c.refs unless c.refs.nil? + end + + heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} + # sort heads so the master is top and current branches are closer + heads.sort! do |a,b| + if a.name == "master" + -1 + elsif b.name == "master" + 1 + else + b.commit.committed_date <=> a.commit.committed_date + end + end + + @_reserved = {} + days.each_index do |i| + @_reserved[i] = [] + end + + heads.each do |h| + if map.include? h.commit.id then + place_chain(map[h.commit.id], map) + end + end + days +end+
# File lib/gitlab/graph_commit.rb, line 107 +def self.mark_reserved(time_range, space) + for day in time_range + @_reserved[day].push(space) + end +end+
# File lib/gitlab/graph_commit.rb, line 148 +def initialize(commit) + @_commit = commit + @time = -1 + @space = 0 +end+
Add space mark on commit and its parents
+ +@param [GraphCommit] the commit object. @param +[Hash<String,GraphCommit>] map of commits
+ + + +# File lib/gitlab/graph_commit.rb, line 73 +def self.place_chain(commit, map, parent_time = nil) + leaves = take_left_leaves(commit, map) + if leaves.empty? then + return + end + space = find_free_space(leaves.last.time..leaves.first.time) + leaves.each{|l| l.space = space} + # and mark it as reserved + min_time = leaves.last.time + parents = leaves.last.parents.collect + parents.each do |p| + if map.include? p.id then + parent = map[p.id] + if parent.time < min_time then + min_time = parent.time + end + end + end + if parent_time.nil? then + max_time = leaves.first.time + else + max_time = parent_time - 1 + end + mark_reserved(min_time..max_time, space) + # Visit branching chains + leaves.each do |l| + parents = l.parents.collect + .select{|p| map.include? p.id and map[p.id].space == 0} + for p in parents + place_chain(map[p.id], map, l.time) + end + end +end+
Takes most left subtree branch of commits which don’t have space mark yet.
+ +@param [GraphCommit] the commit object. @param +[Hash<String,GraphCommit>] map of commits
+ +@return [Array<GraphCommit>] list of branch commits
+ + + +# File lib/gitlab/graph_commit.rb, line 132 +def self.take_left_leaves(commit, map) + leaves = [] + leaves.push(commit) if commit.space == 0 + while true + parent = commit.parents.collect + .select{|p| map.include? p.id and map[p.id].space == 0} + if parent.count == 0 then + return leaves + else + commit = map[parent.first.id] + leaves.push(commit) + end + end +end+
# File lib/gitlab/graph_commit.rb, line 10 +def self.to_graph(project) + @repo = project.repo + commits = Grit::Commit.find_all(@repo, nil, {max_count: 650}) + + ref_cache = {} + + commits.map! {|c| GraphCommit.new(Commit.new(c))} + commits.each { |commit| commit.add_refs(ref_cache, @repo) } + + days = GraphCommit.index_commits(commits) + @days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json + @commits_json = commits.map(&:to_graph_hash).to_json + + return @days_json, @commits_json +end+
# File lib/gitlab/graph_commit.rb, line 174 +def add_refs(ref_cache, repo) + if ref_cache.empty? + repo.refs.each do |ref| + ref_cache[ref.commit.id] ||= [] + ref_cache[ref.commit.id] << ref + end + end + @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) + @refs ||= [] +end+
# File lib/gitlab/graph_commit.rb, line 154 +def method_missing(m, *args, &block) + @_commit.send(m, *args, &block) +end+
# File lib/gitlab/graph_commit.rb, line 158 +def to_graph_hash + h = {} + h[:parents] = self.parents.collect do |p| + [p.id,0,0] + end + h[:author] = Gitlab::Encode.utf8(author.name) + h[:time] = time + h[:space] = space + h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? + h[:id] = sha + h[:date] = date + h[:message] = escape_once(Gitlab::Encode.utf8(message)) + h[:login] = author.email + h +end+
Object + +
# File lib/gitlab/inline_diff.rb, line 42 +def _indexes_of_changed_lines diff_arr + chain_of_first_symbols = "" + diff_arr.each_with_index do |line, i| + chain_of_first_symbols += line[0] + end + chain_of_first_symbols.gsub!(%r[^\-\+]/, "#") + + offset = 0 + indexes = [] + while index = chain_of_first_symbols.index("#-+#", offset) + indexes << index + offset = index + 1 + end + indexes +end+
# File lib/gitlab/inline_diff.rb, line 8 +def processing diff_arr + indexes = _indexes_of_changed_lines diff_arr + + indexes.each do |index| + first_line = diff_arr[index+1] + second_line = diff_arr[index+2] + max_length = [first_line.size, second_line.size].max + + first_the_same_symbols = 0 + (0..max_length + 1).each do |i| + first_the_same_symbols = i - 1 + if first_line[i] != second_line[i] && i > 0 + break + end + end + first_token = first_line[0..first_the_same_symbols][1..-1] + diff_arr[index+1].sub!(first_token, first_token + START) + diff_arr[index+2].sub!(first_token, first_token + START) + last_the_same_symbols = 0 + (1..max_length + 1).each do |i| + last_the_same_symbols = -i + shortest_line = second_line.size > first_line.size ? first_line : second_line + if ( first_line[-i] != second_line[-i] ) || "#{first_token}#{START}".size == shortest_line[1..-i].size + break + end + end + last_the_same_symbols += 1 + last_token = first_line[last_the_same_symbols..-1] + diff_arr[index+1].sub!(%r#{Regexp.escape(last_token)}$/, FINISH + last_token) + diff_arr[index+2].sub!(%r#{Regexp.escape(last_token)}$/, FINISH + last_token) + end + diff_arr +end+
# File lib/gitlab/inline_diff.rb, line 58 +def replace_markers line + line.gsub!(START, "<span class='idiff'>") + line.gsub!(FINISH, "</span>") + line +end+
Grape::API + +
Logger + +
# File lib/gitlab/logger.rb, line 17 +def self.build + new(Rails.root.join("log", file_name)) +end+
# File lib/gitlab/logger.rb, line 3 +def self.error(message) + build.error(message) +end+
# File lib/gitlab/logger.rb, line 7 +def self.info(message) + build.info(message) +end+
# File lib/gitlab/logger.rb, line 11 +def self.read_latest + path = Rails.root.join("log", file_name) + self.build unless File.exist?(path) + logs = File.read(path).split("\n") +end+
Custom parser for GitLab-flavored Markdown
+ +It replaces references in the text with links to the appropriate items in +GitLab.
+ +Supported reference formats are:
+ +* @foo for team members +* #123 for issues +* !123 for merge requests +* $123 for snippets +* 123456 for commits+ +
It also parses Emoji codes to insert images. See www.emoji-cheat-sheet.com/ for +a list of the supported icons.
+ +Examples
+ +>> gfm("Hey @david, can you fix this?") +=> "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?" + +>> gfm("Commit 35d5f7c closes #1234") +=> "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>" + +>> gfm(":trollface:") +=> "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" /> ++ +
Public: Parse the provided text with GitLab-Flavored Markdown
+ +text - the source text #html_options - extra +options for the reference links as given to link_to
+ +Note: reference links will only be generated if @project is set
+ + + +# File lib/gitlab/markdown.rb, line 48 +def gfm(text, html_options = {}) + return text if text.nil? + + # Duplicate the string so we don't alter the original, then call to_str + # to cast it back to a String instead of a SafeBuffer. This is required + # for gsub calls to work as we need them to. + text = text.dup.to_str + + @html_options = html_options + + # Extract pre blocks so they are not altered + # from http://github.github.com/github-flavored-markdown/ + extractions = {} + text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}) do |match| + md5 = Digest::MD5.hexdigest(match) + extractions[md5] = match + "{gfm-extraction-#{md5}}" + end + + # TODO: add popups with additional information + + text = parse(text) + + # Insert pre block extractions + text.gsub!(%r\{gfm-extraction-(\h{32})\}/) do + extractions[$1] + end + + sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class) +end+
Object + +
# File lib/gitlab/merge.rb, line 5 +def initialize(merge_request, user) + @merge_request = merge_request + @project = merge_request.project + @user = user +end+
# File lib/gitlab/merge.rb, line 11 +def can_be_merged? + in_locked_and_timed_satellite do |merge_repo| + merge_in_satellite!(merge_repo) + end +end+
Merges the source branch into the target branch in the satellite and pushes +it back to Gitolite. It also removes the source +branch if requested in the merge request.
+ +Returns false if the merge produced conflicts Returns false if pushing from +the satallite to Gitolite failed or was +rejected Returns true otherwise
+ + + +# File lib/gitlab/merge.rb, line 24 +def merge! + in_locked_and_timed_satellite do |merge_repo| + if merge_in_satellite!(merge_repo) + # push merge back to Gitolite + # will raise CommandFailed when push fails + merge_repo.git.push({raise: true}, :origin, merge_request.target_branch) + + # remove source branch + if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) + # will raise CommandFailed when push fails + merge_repo.git.push({raise: true}, :origin, ":#{merge_request.source_branch}") + end + + # merge, push and branch removal successful + true + end + end +rescue Grit::Git::CommandFailed + false +end+
Grape::API + +
Grape::API + +
Object + +
# File lib/gitlab/satellite.rb, line 8 +def initialize project + self.project = project +end+
will be deleted all branches except PARKING_BRANCH
+ + + +# File lib/gitlab/satellite.rb, line 25 +def clear + Dir.chdir(path) do + heads = Grit::Repo.new(".").heads.map{|head| head.name} + if heads.include? PARKING_BRANCH + %xgit checkout #{PARKING_BRANCH}` + else + %xgit checkout -b #{PARKING_BRANCH}` + end + heads.delete(PARKING_BRANCH) + heads.each do |head| + %xgit branch -D #{head}` + end + end +end+
# File lib/gitlab/satellite.rb, line 12 +def create + %xgit clone #{project.url_to_repo} #{path}` +end+
# File lib/gitlab/satellite.rb, line 20 +def exists? + File.exists? path +end+
# File lib/gitlab/satellite.rb, line 16 +def path + Rails.root.join("tmp", "repo_satellites", project.path) +end+
Grape::API + +
Object + +
# File lib/gitlab/theme.rb, line 3 +def self.css_class_by_id(id) + themes = { + 1 => "ui_basic", + 2 => "ui_mars", + 3 => "ui_modern" + } + + id ||= 1 + + return themes[id] +end+
Grape::API + +
Use this in places where you would normally use link_to(gfm(…), …).
+ +It solves a problem occurring with nested links (i.e. “<a>outer text +<a>gfm ref</a> more outer text</a>”). This will not be +interpreted as intended. Browsers will parse something like “<a>outer +text </a><a>gfm ref</a> more outer text” (notice the last +part is not linked any more). #link_to_gfm +corrects that. It wraps all parts to explicitly produce the correct linking +behavior (i.e. “<a>outer text </a><a>gfm +ref</a><a> more outer text</a>”).
+ + + +# File app/helpers/gitlab_markdown_helper.rb, line 13 +def link_to_gfm(body, url, html_options = {}) + return "" if body.blank? + + gfm_body = gfm(escape_once(body), html_options) + + gfm_body.gsub!(%r{<a.*?>.*?</a>}) do |match| + "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 + end + + link_to(gfm_body.html_safe, url, html_options) +end+
# File app/helpers/gitlab_markdown_helper.rb, line 25 +def markdown(text) + unless @markdown + gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, + # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- + filter_html: true, + with_toc_data: true, + hard_wrap: true) + @markdown = Redcarpet::Markdown.new(gitlab_renderer, + # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use + no_intra_emphasis: true, + tables: true, + fenced_code_blocks: true, + autolink: true, + strikethrough: true, + lax_html_blocks: true, + space_after_headers: true, + superscript: true) + end + + @markdown.render(text).html_safe +end+
Rack::Auth::Basic + +
# File lib/gitlab/backend/grack_auth.rb, line 56 +def can?(object, action, subject) + abilities.allowed?(object, action, subject) +end+
# File lib/gitlab/backend/grack_auth.rb, line 60 +def current_ref + if @env["HTTP_CONTENT_ENCODING"] =~ %rgzip/ + input = Zlib::GzipReader.new(@request.body).read + else + input = @request.body.read + end + # Need to reset seek point + @request.body.rewind + %rrefs\/heads\/([\w-]+)/.match(input).to_a.first +end+
# File lib/gitlab/backend/grack_auth.rb, line 5 +def valid? + # Authentication with username and password + email, password = @auth.credentials + self.user = User.find_by_email(email) + return false unless user.try(:valid_password?, password) + + # Set GL_USER env variable + ENV['GL_USER'] = email + # Pass Gitolite update hook + ENV['GL_BYPASS_UPDATE_HOOK'] = "true" + + # Need this patch due to the rails mount + @env['PATH_INFO'] = @request.path + @env['SCRIPT_NAME'] = "" + + # Find project by PATH_INFO from env + if m = %r^\/([\w-]+).git/.match(@request.path_info).to_a + self.project = Project.find_by_path(m.last) + return false unless project + end + + # Git upload and receive + if @request.get? + validate_get_request + elsif @request.post? + validate_post_request + else + false + end +end+
# File lib/gitlab/backend/grack_auth.rb, line 36 +def validate_get_request + true +end+
# File lib/gitlab/backend/grack_auth.rb, line 40 +def validate_post_request + if @request.path_info.end_with?('git-upload-pack') + can?(user, :push_code, project) + elsif @request.path_info.end_with?('git-receive-pack') + action = if project.protected_branch?(current_ref) + :push_code_to_protected_branches + else + :push_code + end + + can?(user, action, project) + else + false + end +end+
# File lib/gitlab/backend/grack_auth.rb, line 73 +def abilities + @abilities ||= begin + abilities = Six.new + abilities << Ability + abilities + end +end+
ActiveRecord::Base + +
# File app/models/group.rb, line 13 +def self.search query + where("name LIKE :query OR code LIKE :query", query: "%#{query}%") +end+
# File app/models/group.rb, line 17 +def to_param + code +end+
# File app/models/group.rb, line 21 +def users + User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq +end+
Get only assigned issues
+ + + +# File app/controllers/groups_controller.rb, line 26 +def issues + @user = current_user + @issues = current_user.assigned_issues.opened + @issues = @issues.of_group(@group).recent.page(params[:page]).per(20) + @issues = @issues.includes(:author, :project) + + respond_to do |format| + format.html + format.atom { render layout: false } + end +end+
Get authored or assigned open merge requests
+ + + +# File app/controllers/groups_controller.rb, line 20 +def merge_requests + @merge_requests = current_user.cared_merge_requests + @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) +end+
# File app/controllers/groups_controller.rb, line 46 +def people + @users = group.users.all +end+
# File app/controllers/groups_controller.rb, line 38 +def search + result = SearchContext.new(project_ids, params).execute + + @projects = result[:projects] + @merge_requests = result[:merge_requests] + @issues = result[:issues] +end+
# File app/controllers/groups_controller.rb, line 8 +def show + @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) + @last_push = current_user.recent_push + + respond_to do |format| + format.html + format.js + format.atom { render layout: false } + end +end+
# File app/controllers/groups_controller.rb, line 52 +def group + @group ||= Group.find_by_code(params[:id]) +end+
# File app/controllers/groups_controller.rb, line 60 +def project_ids + projects.map(&:id) +end+
# File app/controllers/groups_controller.rb, line 56 +def projects + @projects ||= current_user.projects_with_events.where(group_id: @group.id) +end+
# File app/controllers/help_controller.rb, line 2 +def index +end+
# File app/controllers/hooks_controller.rb, line 13 +def create + @hook = @project.hooks.new(params[:hook]) + @hook.save + + if @hook.valid? + redirect_to project_hooks_path(@project) + else + @hooks = @project.hooks.all + render :index + end +end+
# File app/controllers/hooks_controller.rb, line 31 +def destroy + @hook = @project.hooks.find(params[:id]) + @hook.destroy + + redirect_to project_hooks_path(@project) +end+
# File app/controllers/hooks_controller.rb, line 8 +def index + @hooks = @project.hooks.all + @hook = ProjectHook.new +end+
# File app/controllers/hooks_controller.rb, line 25 +def test + TestHookContext.new(project, current_user, params).execute + + redirect_to :back +end+
ActiveRecord::Base + +
# File app/models/issue.rb, line 14 +def self.open_for(user) + opened.assigned(user) +end+
Contains common functionality shared between Issues and MergeRequests
+ +# File app/roles/issue_commonality.rb, line 50 +def is_assigned? + !!assignee_id +end+
# File app/roles/issue_commonality.rb, line 58 +def is_being_closed? + closed_changed? && closed +end+
# File app/roles/issue_commonality.rb, line 54 +def is_being_reassigned? + assignee_id_changed? +end+
# File app/roles/issue_commonality.rb, line 62 +def is_being_reopened? + closed_changed? && !closed +end+
# File app/roles/issue_commonality.rb, line 46 +def new? + today? && created_at == updated_at +end+
# File app/roles/issue_commonality.rb, line 42 +def today? + Date.today == created_at.to_date +end+
# File app/roles/issue_commonality.rb, line 37 +def search(query) + where("title like :query", query: "%#{query}%") +end+
ActiveRecord::Observer + +
# File app/observers/issue_observer.rb, line 4 +def after_create(issue) + if issue.assignee && issue.assignee != current_user + Notify.new_issue_email(issue.id).deliver + end +end+
# File app/observers/issue_observer.rb, line 10 +def after_update(issue) + send_reassigned_email(issue) if issue.is_being_reassigned? + + status = nil + status = 'closed' if issue.is_being_closed? + status = 'reopened' if issue.is_being_reopened? + if status + Note.create_status_change_note(issue, current_user, status) + [issue.author, issue.assignee].compact.each do |recipient| + Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) + end + end +end+
# File app/observers/issue_observer.rb, line 26 +def send_reassigned_email(issue) + recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } + + recipient_ids.each do |recipient_id| + Notify.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was).deliver + end +end+
BaseContext + +
# File app/contexts/issues_bulk_update_context.rb, line 2 +def execute + update_data = params[:update] + + issues_ids = update_data[:issues_ids].split(",") + milestone_id = update_data[:milestone_id] + assignee_id = update_data[:assignee_id] + status = update_data[:status] + + opts = {} + opts[:milestone_id] = milestone_id if milestone_id.present? + opts[:assignee_id] = assignee_id if assignee_id.present? + opts[:closed] = (status == "closed") if status.present? + + issues = Issue.where(id: issues_ids).all + issues = issues.select { |issue| can?(current_user, :modify_issue, issue) } + issues.each { |issue| issue.update_attributes(opts) } + { + count: issues.count, + success: !issues.count.zero? + } +end+
# File app/controllers/issues_controller.rb, line 111 +def bulk_update + result = IssuesBulkUpdateContext.new(project, current_user, params).execute + redirect_to :back, notice: "#{result[:count]} issues updated" +end+
# File app/controllers/issues_controller.rb, line 48 +def create + @issue = @project.issues.new(params[:issue]) + @issue.author = current_user + @issue.save + + respond_to do |format| + format.html do + if @issue.valid? + redirect_to project_issue_path(@project, @issue) + else + render :new + end + end + format.js + end +end+
# File app/controllers/issues_controller.rb, line 80 +def destroy + @issue.destroy + + respond_to do |format| + format.html { redirect_to project_issues_path } + format.js { render nothing: true } + end +end+
# File app/controllers/issues_controller.rb, line 35 +def edit + respond_with(@issue) +end+
# File app/controllers/issues_controller.rb, line 19 +def index + @issues = issues_filtered + @issues = @issues.page(params[:page]).per(20) + + respond_to do |format| + format.html # index.html.erb + format.js + format.atom { render layout: false } + end +end+
# File app/controllers/issues_controller.rb, line 30 +def new + @issue = @project.issues.new(params[:issue]) + respond_with(@issue) +end+
# File app/controllers/issues_controller.rb, line 101 +def search + terms = params['terms'] + + @issues = issues_filtered + @issues = @issues.where("title LIKE ?", "%#{terms}%") unless terms.blank? + @issues = @issues.page(params[:page]).per(100) + + render partial: 'issues' +end+
# File app/controllers/issues_controller.rb, line 39 +def show + @note = @project.notes.new(noteable: @issue) + + respond_to do |format| + format.html + format.js + end +end+
# File app/controllers/issues_controller.rb, line 89 +def sort + return render_404 unless can?(current_user, :admin_issue, @project) + + @issues = @project.issues.where(id: params['issue']) + @issues.each do |issue| + issue.position = params['issue'].index(issue.id.to_s) + 1 + issue.save + end + + render nothing: true +end+
# File app/controllers/issues_controller.rb, line 65 +def update + @issue.update_attributes(params[:issue].merge(author_id_of_changes: current_user.id)) + + respond_to do |format| + format.js + format.html do + if @issue.valid? + redirect_to [@project, @issue] + else + render :edit + end + end + end +end+
# File app/controllers/issues_controller.rb, line 118 +def issue + @issue ||= @project.issues.find(params[:id]) +end+
# File app/controllers/issues_controller.rb, line 134 +def issues_filtered + @issues = IssuesListContext.new(project, current_user, params).execute +end+
# File app/controllers/issues_controller.rb, line 130 +def module_enabled + return render_404 unless @project.issues_enabled +end+
# File app/helpers/issues_helper.rb, line 29 +def issue_css_classes issue + classes = "issue" + classes << " closed" if issue.closed + classes << " today" if issue.today? + classes +end+
# File app/helpers/issues_helper.rb, line 47 +def issues_filter + { + all: "all", + closed: "closed", + to_me: "assigned-to-me", + open: "open" + } +end+
# File app/helpers/issues_helper.rb, line 7 +def link_to_issue_assignee(issue) + project = issue.project + + tm = project.team_member_by_id(issue.assignee_id) + if tm + link_to issue.assignee_name, project_team_member_path(project, tm), class: "author_link" + else + issue.assignee_name + end +end+
# File app/helpers/issues_helper.rb, line 2 +def project_issues_filter_path project, params = {} + params[:f] ||= cookies['issue_filter'] + project_issues_path project, params +end+
Returns an OpenStruct object suitable for use by
+options_from_collection_for_select
to allow filtering issues
+by an unassigned User or Milestone
# File app/helpers/issues_helper.rb, line 42 +def unassigned_filter + # Milestone uses :title, Issue uses :name + OpenStruct.new(id: 0, title: 'Unspecified', name: 'Unassigned') +end+
BaseContext + +
# File app/contexts/issues_list_context.rb, line 6 +def execute + @issues = case params[:f] + when issues_filter[:all] then @project.issues + when issues_filter[:closed] then @project.issues.closed + when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) + else @project.issues.opened + end + + @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present? + @issues = @issues.includes(:author, :project).order("updated_at") + + # Filter by specific assignee_id (or lack thereof)? + if params[:assignee_id].present? + @issues = @issues.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id])) + end + + # Filter by specific milestone_id (or lack thereof)? + if params[:milestone_id].present? + @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id])) + end + + @issues +end+
ActiveRecord::Base + +
# File app/models/key.rb, line 30 +def fingerprintable_key + return true unless key # Don't test if there is no key. + # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected + file = Tempfile.new('key_file') + begin + file.puts key + file.rewind + fingerprint_output = %xssh-keygen -lf #{file.path} 2>&1` # Catch stderr. + ensure + file.close + file.unlink # deletes the temp file + end + errors.add(:key, "can't be fingerprinted") if fingerprint_output.match("failed") +end+
# File app/models/key.rb, line 53 +def is_deploy_key + true if project_id +end+
# File app/models/key.rb, line 66 +def last_deploy? + Key.where(identifier: identifier).count == 0 +end+
projects that has this key
+ + + +# File app/models/key.rb, line 58 +def projects + if is_deploy_key + [project] + else + user.projects + end +end+
# File app/models/key.rb, line 45 +def set_identifier + if is_deploy_key + self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}" + else + self.identifier = "#{user.identifier}_#{Time.now.to_i}" + end +end+
# File app/models/key.rb, line 18 +def strip_white_space + self.key = self.key.strip unless self.key.blank? +end+
# File app/models/key.rb, line 22 +def unique_key + query = Key.where(key: key) + query = query.where('(project_id IS NULL OR project_id = ?)', project_id) if project_id + if (query.count > 0) + errors.add :key, 'already exist.' + end +end+
ActiveRecord::Observer + +
# File app/observers/key_observer.rb, line 8 +def after_destroy(key) + return if key.is_deploy_key && !key.last_deploy? + git_host.remove_key(key.identifier, key.projects) +end+
# File app/observers/key_observer.rb, line 4 +def after_save(key) + git_host.set_key(key.identifier, key.key, key.projects) +end+
# File app/controllers/keys_controller.rb, line 19 +def create + @key = current_user.keys.new(params[:key]) + @key.save + + respond_with(@key) +end+
# File app/controllers/keys_controller.rb, line 26 +def destroy + @key = current_user.keys.find(params[:id]) + @key.destroy + + respond_to do |format| + format.html { redirect_to keys_url } + format.js { render nothing: true } + end +end+
# File app/controllers/keys_controller.rb, line 5 +def index + @keys = current_user.keys.all +end+
# File app/controllers/keys_controller.rb, line 13 +def new + @key = current_user.keys.new + + respond_with(@key) +end+
# File app/controllers/keys_controller.rb, line 9 +def show + @key = current_user.keys.find(params[:id]) +end+
# File app/controllers/labels_controller.rb, line 9 +def index + @labels = @project.issues_labels.order('count DESC') +end+
# File app/controllers/labels_controller.rb, line 15 +def module_enabled + return render_404 unless @project.issues_enabled +end+
ActiveRecord::Base + +
# File app/models/merge_request.rb, line 25 +def self.find_all_by_branch(branch_name) + where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) +end+
# File app/models/merge_request.rb, line 169 +def automerge!(current_user) + if Gitlab::Merge.new(self, current_user).merge! && self.unmerged_commits.empty? + self.merge!(current_user.id) + true + end +rescue + self.mark_as_unmergable + false +end+
# File app/models/merge_request.rb, line 86 +def broken_diffs? + diffs == [BROKEN_DIFF] +end+
# File app/models/merge_request.rb, line 58 +def can_be_merged? + state == CAN_BE_MERGED +end+
# File app/models/merge_request.rb, line 62 +def check_if_can_be_merged + self.state = if Gitlab::Merge.new(self, self.author).can_be_merged? + CAN_BE_MERGED + else + CANNOT_BE_MERGED + end + self.save +end+
# File app/models/merge_request.rb, line 114 +def closed_event + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Closed).last +end+
# File app/models/merge_request.rb, line 118 +def commits + st_commits || [] +end+
# File app/models/merge_request.rb, line 71 +def diffs + st_diffs || [] +end+
# File app/models/merge_request.rb, line 29 +def human_state + states = { + CAN_BE_MERGED => "can_be_merged", + CANNOT_BE_MERGED => "cannot_be_merged", + UNCHECKED => "unchecked" + } + states[self.state] +end+
# File app/models/merge_request.rb, line 102 +def last_commit + commits.first +end+
# File app/models/merge_request.rb, line 131 +def mark_as_merged! + self.merged = true + self.closed = true + save +end+
# File app/models/merge_request.rb, line 53 +def mark_as_unchecked + self.state = UNCHECKED + self.save +end+
# File app/models/merge_request.rb, line 137 +def mark_as_unmergable + self.state = CANNOT_BE_MERGED + self.save +end+
# File app/models/merge_request.rb, line 158 +def merge!(user_id) + self.mark_as_merged! + Event.create( + project: self.project, + action: Event::Merged, + target_id: self.id, + target_type: "MergeRequest", + author_id: user_id + ) +end+
# File app/models/merge_request.rb, line 110 +def merge_event + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Merged).last +end+
# File app/models/merge_request.rb, line 106 +def merged? + merged && merge_event +end+
# File app/models/merge_request.rb, line 191 +def mr_and_commit_notes + commit_ids = commits.map(&:id) + Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND noteable_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) +end+
# File app/models/merge_request.rb, line 127 +def open? + !closed +end+
# File app/models/merge_request.rb, line 122 +def probably_merged? + unmerged_commits.empty? && + commits.any? && open? +end+
# File app/models/merge_request.rb, line 44 +def reload_code + self.reloaded_commits + self.reloaded_diffs +end+
# File app/models/merge_request.rb, line 142 +def reloaded_commits + if open? && unmerged_commits.any? + self.st_commits = unmerged_commits + save + end + commits +end+
# File app/models/merge_request.rb, line 75 +def reloaded_diffs + if open? && unmerged_diffs.any? + self.st_diffs = unmerged_diffs + self.save + end + +rescue Grit::Git::GitTimeout + self.st_diffs = [BROKEN_DIFF] + self.save +end+
# File app/models/merge_request.rb, line 179 +def to_raw + FileUtils.mkdir_p(Rails.root.join("tmp", "patches")) + patch_path = Rails.root.join("tmp", "patches", "merge_request_#{self.id}.patch") + + from = commits.last.id + to = source_branch + + project.repo.git.run('', "format-patch" , " > #{patch_path.to_s}", {}, ["#{from}..#{to}", "--stdout"]) + + patch_path +end+
# File app/models/merge_request.rb, line 49 +def unchecked? + state == UNCHECKED +end+
# File app/models/merge_request.rb, line 150 +def unmerged_commits + self.project.repo. + commits_between(self.target_branch, self.source_branch). + map {|c| Commit.new(c)}. + sort_by(&:created_at). + reverse +end+
# File app/models/merge_request.rb, line 94 +def unmerged_diffs + # Only show what is new in the source branch compared to the target branch, not the other way around. + # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2) + # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B" + common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip + diffs = project.repo.diff(common_commit, source_branch) +end+
# File app/models/merge_request.rb, line 90 +def valid_diffs? + !broken_diffs? +end+
# File app/models/merge_request.rb, line 38 +def validate_branches + if target_branch == source_branch + errors.add :base, "You can not use same branch for source and target branches" + end +end+
ActiveRecord::Observer + +
# File app/observers/merge_request_observer.rb, line 4 +def after_create(merge_request) + if merge_request.assignee && merge_request.assignee != current_user + Notify.new_merge_request_email(merge_request.id).deliver + end +end+
# File app/observers/merge_request_observer.rb, line 10 +def after_update(merge_request) + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? + + status = nil + status = 'closed' if merge_request.is_being_closed? + status = 'reopened' if merge_request.is_being_reopened? + if status + Note.create_status_change_note(merge_request, current_user, status) + end +end+
# File app/observers/merge_request_observer.rb, line 23 +def send_reassigned_email(merge_request) + recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id + recipients_ids.delete current_user.id + + recipients_ids.each do |recipient_id| + Notify.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was).deliver + end +end+
# File app/controllers/merge_requests_controller.rb, line 79 +def automerge + return access_denied! unless can?(current_user, :accept_mr, @project) + if @merge_request.open? && @merge_request.can_be_merged? + @merge_request.should_remove_source_branch = params[:should_remove_source_branch] + @merge_request.automerge!(current_user) + @status = true + else + @status = false + end +end+
# File app/controllers/merge_requests_controller.rb, line 72 +def automerge_check + if @merge_request.unchecked? + @merge_request.check_if_can_be_merged + end + render json: {state: @merge_request.human_state} +end+
# File app/controllers/merge_requests_controller.rb, line 98 +def branch_from + @commit = project.commit(params[:ref]) + @commit = CommitDecorator.decorate(@commit) +end+
# File app/controllers/merge_requests_controller.rb, line 103 +def branch_to + @commit = project.commit(params[:ref]) + @commit = CommitDecorator.decorate(@commit) +end+
# File app/controllers/merge_requests_controller.rb, line 50 +def create + @merge_request = @project.merge_requests.new(params[:merge_request]) + @merge_request.author = current_user + + if @merge_request.save + @merge_request.reload_code + redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' + else + render action: "new" + end +end+
# File app/controllers/merge_requests_controller.rb, line 90 +def destroy + @merge_request.destroy + + respond_to do |format| + format.html { redirect_to project_merge_requests_url(@project) } + end +end+
# File app/controllers/merge_requests_controller.rb, line 35 +def diffs + @diffs = @merge_request.diffs + @commit = @merge_request.last_commit + + @comments_allowed = true + @line_notes = @merge_request.notes.where("line_code is not null") +end+
# File app/controllers/merge_requests_controller.rb, line 47 +def edit +end+
# File app/controllers/merge_requests_controller.rb, line 20 +def index + @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute +end+
# File app/controllers/merge_requests_controller.rb, line 43 +def new + @merge_request = @project.merge_requests.new(params[:merge_request]) +end+
# File app/controllers/merge_requests_controller.rb, line 31 +def raw + send_file @merge_request.to_raw +end+
# File app/controllers/merge_requests_controller.rb, line 24 +def show + respond_to do |format| + format.html + format.js + end +end+
# File app/controllers/merge_requests_controller.rb, line 62 +def update + if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) + @merge_request.reload_code + @merge_request.mark_as_unchecked + redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' + else + render action: "edit" + end +end+
# File app/controllers/merge_requests_controller.rb, line 135 +def define_show_vars + # Build a note object for comment form + @note = @project.notes.new(noteable: @merge_request) + + # Get commits from repository + # or from cache if already merged + @commits = @merge_request.commits + @commits = CommitDecorator.decorate(@commits) +end+
# File app/controllers/merge_requests_controller.rb, line 110 +def merge_request + @merge_request ||= @project.merge_requests.find(params[:id]) +end+
# File app/controllers/merge_requests_controller.rb, line 122 +def module_enabled + return render_404 unless @project.merge_requests_enabled +end+
# File app/controllers/merge_requests_controller.rb, line 126 +def validates_merge_request + # Show git not found page if target branch doesnt exist + return git_not_found! unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) + + # Show git not found page if source branch doesnt exist + # and there is no saved commits between source & target branch + return git_not_found! if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank? +end+
# File app/helpers/merge_requests_helper.rb, line 2 +def link_to_merge_request_assignee(merge_request) + project = merge_request.project + + tm = project.team_member_by_id(merge_request.assignee_id) + if tm + link_to merge_request.assignee_name, project_team_member_path(project, tm), class: "author_link" + else + merge_request.assignee_name + end +end+
# File app/helpers/merge_requests_helper.rb, line 35 +def mr_css_classes mr + classes = "merge_request" + classes << " closed" if mr.closed + classes << " merged" if mr.merged? + classes +end+
# File app/helpers/merge_requests_helper.rb, line 24 +def new_mr_path_from_push_event(event) + new_project_merge_request_path( + event.project, + merge_request: { + source_branch: event.branch_name, + target_branch: event.project.root_ref, + title: event.branch_name.titleize + } + ) +end+
BaseContext + +
# File app/contexts/merge_requests_load_context.rb, line 2 +def execute + type = params[:f] + + merge_requests = project.merge_requests + + merge_requests = case type + when 'all' then merge_requests + when 'closed' then merge_requests.closed + when 'assigned-to-me' then merge_requests.opened.assigned(current_user) + else merge_requests.opened + end.page(params[:page]).per(20) + + merge_requests.includes(:author, :project).order("closed, created_at desc") +end+
ActiveRecord::Base + +
# File app/models/milestone.rb, line 10 +def self.active + where("due_date > ? OR due_date IS NULL", Date.today) +end+
# File app/models/milestone.rb, line 24 +def expires_at + "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date +end+
# File app/models/milestone.rb, line 14 +def participants + User.where(id: issues.pluck(:assignee_id)) +end+
# File app/models/milestone.rb, line 18 +def percent_complete + ((self.issues.closed.count * 100) / self.issues.count).abs +rescue ZeroDivisionError + 100 +end+
# File app/controllers/milestones_controller.rb, line 42 +def create + @milestone = @project.milestones.new(params[:milestone]) + + if @milestone.save + redirect_to project_milestone_path(@project, @milestone) + else + render "new" + end +end+
# File app/controllers/milestones_controller.rb, line 67 +def destroy + return access_denied! unless can?(current_user, :admin_milestone, @milestone) + + @milestone.destroy + + respond_to do |format| + format.html { redirect_to project_milestones_path } + format.js { render nothing: true } + end +end+
# File app/controllers/milestones_controller.rb, line 28 +def edit + respond_with(@milestone) +end+
# File app/controllers/milestones_controller.rb, line 13 +def index + @milestones = case params[:f] + when 'all'; @project.milestones + else @project.milestones.active + end + + @milestones = @milestones.includes(:project).order("due_date") + @milestones = @milestones.page(params[:page]).per(20) +end+
# File app/controllers/milestones_controller.rb, line 23 +def new + @milestone = @project.milestones.new + respond_with(@milestone) +end+
# File app/controllers/milestones_controller.rb, line 32 +def show + @issues = @milestone.issues + @users = @milestone.participants + + respond_to do |format| + format.html + format.js + end +end+
# File app/controllers/milestones_controller.rb, line 52 +def update + @milestone.update_attributes(params[:milestone]) + + respond_to do |format| + format.js + format.html do + if @milestone.valid? + redirect_to [@project, @milestone] + else + render :edit + end + end + end +end+
# File app/controllers/milestones_controller.rb, line 80 +def milestone + @milestone ||= @project.milestones.find(params[:id]) +end+
# File app/controllers/milestones_controller.rb, line 88 +def module_enabled + return render_404 unless @project.issues_enabled +end+
ActiveRecord::Base + +
# File app/models/note.rb, line 34 +def self.create_status_change_note(noteable, author, status) + create({ + noteable: noteable, + project: noteable.project, + author: author, + note: "_Status changed to #{status}_" + }, without_protection: true) +end+
Returns true if this is a downvote note, otherwise false is returned
+ + + +# File app/models/note.rb, line 106 +def downvote? + note.start_with?('-1') || note.start_with?(':-1:') +end+
# File app/models/note.rb, line 82 +def for_commit? + noteable_type == "Commit" +end+
# File app/models/note.rb, line 86 +def for_diff_line? + line_code.present? +end+
override to return commits, which are not active record
+ + + +# File app/models/note.rb, line 52 +def noteable + if for_commit? + project.commit(noteable_id) + else + super + end +# Temp fix to prevent app crash +# if note commit id doesnt exist +rescue + nil +end+
Returns true if this is an upvote note, otherwise false is returned
+ + + +# File app/models/note.rb, line 100 +def upvote? + note.start_with?('+1') || note.start_with?(':+1:') +end+
ActiveRecord::Observer + +
# File app/observers/note_observer.rb, line 3 +def after_create(note) + send_notify_mails(note) +end+
Notifies the whole team except the author of note
+ + + +# File app/observers/note_observer.rb, line 22 +def notify_team(note) + # Note: wall posts are not "attached" to anything, so fall back to "Wall" + noteable_type = note.noteable_type || "Wall" + notify_method = "note_#{noteable_type.underscore}_email".to_sym + + if Notify.respond_to? notify_method + team_without_note_author(note).map do |u| + Notify.send(notify_method, u.id, note.id).deliver + end + end +end+
# File app/observers/note_observer.rb, line 9 +def send_notify_mails(note) + if note.notify + notify_team(note) + elsif note.notify_author + # Notify only author of resource + Notify.note_commit_email(note.commit_author.id, note.id).deliver + else + # Otherwise ignore it + nil + end +end+
BaseContext + +
# File app/contexts/notes/create_context.rb, line 3 +def execute + note = project.notes.new(params[:note]) + note.author = current_user + note.notify = true if params[:notify] == '1' + note.notify_author = true if params[:notify_author] == '1' + note.save + note +end+
BaseContext + +
# File app/contexts/notes/load_context.rb, line 3 +def execute + target_type = params[:target_type] + target_id = params[:target_id] + after_id = params[:after_id] + before_id = params[:before_id] + + + @notes = case target_type + when "commit" + project.commit_notes(project.commit(target_id)).fresh.limit(20) + when "issue" + project.issues.find(target_id).notes.inc_author.fresh.limit(20) + when "merge_request" + project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh.limit(20) + when "snippet" + project.snippets.find(target_id).notes.fresh + when "wall" + # this is the only case, where the order is DESC + project.common_notes.order("created_at DESC, id DESC").limit(50) + when "wiki" + project.wiki_notes.limit(20) + end + + @notes = if after_id + @notes.where("id > ?", after_id) + elsif before_id + @notes.where("id < ?", before_id) + else + @notes + end +end+
# File app/controllers/notes_controller.rb, line 18 +def create + @note = Notes::CreateContext.new(project, current_user, params).execute + + respond_to do |format| + format.html {redirect_to :back} + format.js + end +end+
# File app/controllers/notes_controller.rb, line 27 +def destroy + @note = @project.notes.find(params[:id]) + return access_denied! unless can?(current_user, :admin_note, @note) + @note.destroy + + respond_to do |format| + format.js { render nothing: true } + end +end+
# File app/controllers/notes_controller.rb, line 8 +def index + notes + if params[:target_type] == "merge_request" + @mixed_targets = true + @main_target_type = params[:target_type].camelize + end + + respond_with(@notes) +end+
# File app/controllers/notes_controller.rb, line 37 +def preview + render text: view_context.markdown(params[:note]) +end+
# File app/controllers/notes_controller.rb, line 43 +def notes + @notes = Notes::LoadContext.new(project, current_user, params).execute +end+
# File app/helpers/notes_helper.rb, line 15 +def link_to_commit_diff_line_note(note) + commit = note.noteable + diff_index, diff_old_line, diff_new_line = note.line_code.split('_') + + link_file = commit.diffs[diff_index.to_i].new_path + link_line = diff_new_line + + link_to "#{link_file}:L#{link_line}", project_commit_path(@project, commit, anchor: note.line_code) +end+
# File app/helpers/notes_helper.rb, line 2 +def loading_more_notes? + params[:loading_more].present? +end+
# File app/helpers/notes_helper.rb, line 6 +def loading_new_notes? + params[:loading_new].present? +end+
Helps to distinguish e.g. commit notes in mr notes list
+ + + +# File app/helpers/notes_helper.rb, line 11 +def note_for_main_target?(note) + !@mixed_targets || @main_target_type == note.noteable_type +end+
ActionMailer::Base + +
# File app/mailers/notify.rb, line 31 +def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) + @issue = Issue.find issue_id + @issue_status = status + @updated_by = User.find updated_by_user_id + mail(to: recipient(recipient_id), + subject: subject("changed issue ##{@issue.id}", @issue.title)) +end+
# File app/mailers/notify.rb, line 18 +def new_issue_email(issue_id) + @issue = Issue.find(issue_id) + @project = @issue.project + mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title)) +end+
Merge Request
+ + + +# File app/mailers/notify.rb, line 45 +def new_merge_request_email(merge_request_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) +end+
# File app/mailers/notify.rb, line 118 +def new_user_email(user_id, password) + @user = User.find(user_id) + @password = password + mail(to: @user.email, subject: subject("Account was created for you")) +end+
# File app/mailers/notify.rb, line 64 +def note_commit_email(recipient_id, note_id) + @note = Note.find(note_id) + @commit = @note.noteable + @commit = CommitDecorator.decorate(@commit) + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) +end+
# File app/mailers/notify.rb, line 72 +def note_issue_email(recipient_id, note_id) + @note = Note.find(note_id) + @issue = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}")) +end+
# File app/mailers/notify.rb, line 79 +def note_merge_request_email(recipient_id, note_id) + @note = Note.find(note_id) + @merge_request = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}")) +end+
# File app/mailers/notify.rb, line 86 +def note_wall_email(recipient_id, note_id) + @note = Note.find(note_id) + @project = @note.project + mail(to: recipient(recipient_id), subject: subject) +end+
# File app/mailers/notify.rb, line 92 +def note_wiki_email(recipient_id, note_id) + @note = Note.find(note_id) + @wiki = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for wiki")) +end+
# File app/mailers/notify.rb, line 105 +def project_access_granted_email(user_project_id) + @users_project = UsersProject.find user_project_id + @project = @users_project.project + mail(to: @users_project.user.email, + subject: subject("access to project was granted")) +end+
# File app/mailers/notify.rb, line 24 +def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) + @issue = Issue.find(issue_id) + @previous_assignee ||= User.find(previous_assignee_id) + @project = @issue.project + mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) +end+
# File app/mailers/notify.rb, line 51 +def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) + @merge_request = MergeRequest.find(merge_request_id) + @previous_assignee ||= User.find(previous_assignee_id) + @project = @merge_request.project + mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) +end+
Devise::OmniauthCallbacksController + +
Extend the standard message generation to accept our custom exception
+ + + +# File app/controllers/omniauth_callbacks_controller.rb, line 9 +def failure_message + exception = env["omniauth.error"] + error = exception.error_reason if exception.respond_to?(:error_reason) + error ||= exception.error if exception.respond_to?(:error) + error ||= exception.message if exception.respond_to?(:message) + error ||= env["omniauth.error.type"].to_s + error.to_s.humanize if error +end+
# File app/controllers/omniauth_callbacks_controller.rb, line 18 +def ldap + # We only find ourselves here if the authentication to LDAP was successful. + @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) + if @user.persisted? + @user.remember_me = true + end + sign_in_and_redirect @user +end+
Object + +
# File app/workers/post_receive.rb, line 4 +def self.perform(reponame, oldrev, newrev, ref, identifier) + project = Project.find_by_path(reponame) + return false if project.nil? + + # Ignore push from non-gitlab users + if %r^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) + return false unless user = User.find_by_email(identifier) + else + return false unless user = Key.find_by_identifier(identifier).try(:user) + end + + project.trigger_post_receive(oldrev, newrev, ref, user) +end+
# File app/controllers/profile_controller.rb, line 7 +def design +end+
# File app/controllers/profile_controller.rb, line 34 +def history + @events = current_user.recent_events.page(params[:page]).per(20) +end+
# File app/controllers/profile_controller.rb, line 18 +def password_update + params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"} + + if @user.update_attributes(params[:user]) + flash[:notice] = "Password was successfully updated. Please login with it" + redirect_to new_user_session_path + else + render action: "password" + end +end+
# File app/controllers/profile_controller.rb, line 29 +def reset_private_token + current_user.reset_authentication_token! + redirect_to profile_account_path +end+
# File app/controllers/profile_controller.rb, line 4 +def show +end+
# File app/controllers/profile_controller.rb, line 15 +def token +end+
# File app/controllers/profile_controller.rb, line 10 +def update + @user.update_attributes(params[:user]) + redirect_to :back +end+
# File app/helpers/profile_helper.rb, line 2 +def oauth_active_class provider + if current_user.provider == provider.to_s + 'active' + end +end+
ActiveRecord::Base + +
# File app/models/project.rb, line 85 +def access_options + UsersProject.access_roles +end+
# File app/models/project.rb, line 52 +def active + joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") +end+
# File app/models/project.rb, line 60 +def create_by_user(params, user) + project = Project.new params + + Project.transaction do + project.owner = user + project.save! + + # Add user as project master + project.users_projects.create!(project_access: UsersProject::MASTER, user: user) + + # when project saved no team member exist so + # project repository should be updated after first user add + project.update_repository + end + + project +rescue Gitlab::Gitolite::AccessDenied => ex + project.error_code = :gitolite + project +rescue => ex + project.error_code = :db + project.errors.add(:base, "Can't save project. Please try again later") + project +end+
# File app/models/project.rb, line 56 +def search query + where("name LIKE :query OR code LIKE :query OR path LIKE :query", query: "%#{query}%") +end+
# File app/models/project.rb, line 124 +def build_commit_note(commit) + notes.new(noteable_id: commit.id, noteable_type: "Commit") +end+
# File app/models/project.rb, line 98 +def check_limit + unless owner.can_create_project? + errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") + end +rescue + errors[:base] << ("Can't check your ability to create project") +end+
# File app/models/project.rb, line 132 +def commit_line_notes(commit) + notes.where(noteable_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") +end+
# File app/models/project.rb, line 128 +def commit_notes(commit) + notes.where(noteable_id: commit.id, noteable_type: "Commit", line_code: nil) +end+
# File app/models/project.rb, line 120 +def common_notes + notes.where(noteable_type: ["", nil]).inc_author_project +end+
# File app/models/project.rb, line 90 +def git_error? + error_code == :gitolite +end+
# File app/models/project.rb, line 160 +def issues_labels + issues.tag_counts_on(:labels) +end+
# File app/models/project.rb, line 144 +def last_activity + last_event +end+
# File app/models/project.rb, line 148 +def last_activity_date + last_event.try(:created_at) || updated_at +end+
# File app/models/project.rb, line 140 +def private? + private_flag +end+
# File app/models/project.rb, line 156 +def project_id + self.id +end+
# File app/models/project.rb, line 136 +def public? + !private_flag +end+
# File app/models/project.rb, line 106 +def repo_name + if path == "gitolite-admin" + errors.add(:path, " like 'gitolite-admin' is not allowed") + end +end+
# File app/models/project.rb, line 94 +def saved? + id && valid? +end+
# File app/models/project.rb, line 112 +def to_param + code +end+
# File app/models/project.rb, line 116 +def web_url + [Gitlab.config.url, code].join("/") +end+
# File app/models/project.rb, line 152 +def wiki_notes + Note.where(noteable_id: wikis.pluck(:id), noteable_type: 'Wiki', project_id: self.id) +end+
WebHook + +
ActiveRecord::Observer + +
# File app/observers/project_observer.rb, line 12 +def after_create project + log_info("#{project.owner.name} created a new project \"#{project.name}\"") +end+
# File app/observers/project_observer.rb, line 6 +def after_destroy(project) + log_info("Project \"#{project.name}\" was removed") + + project.destroy_repository +end+
# File app/observers/project_observer.rb, line 2 +def after_save(project) + project.update_repository +end+
# File app/observers/project_observer.rb, line 18 +def log_info message + Gitlab::AppLogger.info message +end+
# File app/controllers/projects_controller.rb, line 20 +def create + @project = Project.create_by_user(params[:project], current_user) + + respond_to do |format| + format.html do + if @project.saved? + redirect_to(@project, notice: 'Project was successfully created.') + else + render action: "new" + end + end + format.js + end +end+
# File app/controllers/projects_controller.rb, line 85 +def destroy + # Disable the UsersProject update_repository call, otherwise it will be + # called once for every person removed from the project + UsersProject.skip_callback(:destroy, :after, :update_repository) + project.destroy + UsersProject.set_callback(:destroy, :after, :update_repository) + + respond_to do |format| + format.html { redirect_to root_path } + end +end+
# File app/controllers/projects_controller.rb, line 17 +def edit +end+
# File app/controllers/projects_controller.rb, line 64 +def files + @notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100) +end+
# File app/controllers/projects_controller.rb, line 81 +def graph + @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project) +end+
# File app/controllers/projects_controller.rb, line 13 +def new + @project = Project.new +end+
# File app/controllers/projects_controller.rb, line 47 +def show + limit = (params[:limit] || 20).to_i + @events = @project.events.recent.limit(limit).offset(params[:offset] || 0) + + respond_to do |format| + format.html do + unless @project.empty_repo? + @last_push = current_user.recent_push(@project.id) + render :show + else + render "projects/empty" + end + end + format.js + end +end+
# File app/controllers/projects_controller.rb, line 35 +def update + respond_to do |format| + if project.update_attributes(params[:project]) + format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' } + format.js + else + format.html { render action: "edit" } + format.js + end + end +end+
Wall
+ + + +# File app/controllers/projects_controller.rb, line 72 +def wall + return render_404 unless @project.wall_enabled + @note = Note.new + + respond_to do |format| + format.html + end +end+
# File app/helpers/projects_helper.rb, line 2 +def grouper_project_members(project) + @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) +end+
# File app/helpers/projects_helper.rb, line 10 +def link_to_project project + link_to project.name, project +end+
# File app/helpers/projects_helper.rb, line 6 +def remove_from_team_message(project, member) + "You are going to remove #{member.user_name} from #{project.name}. Are you sure?" +end+
ActiveRecord::Base + +
# File app/models/protected_branch.rb, line 17 +def commit + project.commit(self.name) +end+
# File app/models/protected_branch.rb, line 13 +def update_repository + git_host.update_repository(project) +end+
# File app/controllers/protected_branches_controller.rb, line 13 +def create + @project.protected_branches.create(params[:protected_branch]) + redirect_to project_protected_branches_path(@project) +end+
# File app/controllers/protected_branches_controller.rb, line 18 +def destroy + @project.protected_branches.find(params[:id]).destroy + + respond_to do |format| + format.html { redirect_to project_protected_branches_path } + format.js { render nothing: true } + end +end+
# File app/controllers/protected_branches_controller.rb, line 8 +def index + @branches = @project.protected_branches.all + @protected_branch = @project.protected_branches.new +end+
# File app/roles/push_event.rb, line 12 +def branch? + data[:ref]["refs/heads"] +end+
# File app/roles/push_event.rb, line 48 +def branch_name + @branch_name ||= data[:ref].gsub("refs/heads/", "") +end+
# File app/roles/push_event.rb, line 32 +def commit_from + data[:before] +end+
# File app/roles/push_event.rb, line 36 +def commit_to + data[:after] +end+
Max 20 commits from push DESC
+ + + +# File app/roles/push_event.rb, line 57 +def commits + @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse +end+
# File app/roles/push_event.rb, line 61 +def commits_count + data[:total_commits_count] || commits.count || 0 +end+
# File app/roles/push_event.rb, line 85 +def last_commit + project.commit(commit_to) +rescue => ex + nil +end+
# File app/roles/push_event.rb, line 97 +def last_push_to_non_root? + branch? && project.default_branch != branch_name +end+
# File app/roles/push_event.rb, line 28 +def md_ref? + !(rm_ref? || new_ref?) +end+
# File app/roles/push_event.rb, line 16 +def new_branch? + commit_from =~ %r^00000/ +end+
# File app/roles/push_event.rb, line 20 +def new_ref? + commit_from =~ %r^00000/ +end+
# File app/roles/push_event.rb, line 79 +def parent_commit + project.commit(commit_from) +rescue => ex + nil +end+
# File app/roles/push_event.rb, line 69 +def push_action_name + if new_ref? + "pushed new" + elsif rm_ref? + "deleted" + else + "pushed to" + end +end+
# File app/roles/push_event.rb, line 91 +def push_with_commits? + md_ref? && commits.any? && parent_commit && last_commit +rescue Grit::NoSuchPathError + false +end+
# File app/roles/push_event.rb, line 40 +def ref_name + if tag? + tag_name + else + branch_name + end +end+
# File app/roles/push_event.rb, line 65 +def ref_type + tag? ? "tag" : "branch" +end+
# File app/roles/push_event.rb, line 24 +def rm_ref? + commit_to =~ %r^00000/ +end+
# File app/roles/push_event.rb, line 8 +def tag? + data[:ref]["refs/tags"] +end+
# File app/roles/push_event.rb, line 52 +def tag_name + @tag_name ||= data[:ref].gsub("refs/tags/", "") +end+
# File app/roles/push_event.rb, line 2 +def valid_push? + data[:ref] +rescue => ex + false +end+
Includes methods for handling Git Push events
+ +Triggered by PostReceive job
+ +# File app/roles/push_observer.rb, line 33 +def execute_hooks(oldrev, newrev, ref, user) + ref_parts = ref.split('/') + + # Return if this is not a push to a branch (e.g. new commits) + return if ref_parts[1] !~ %rheads/ || oldrev == "00000000000000000000000000000000" + + data = post_receive_data(oldrev, newrev, ref, user) + + hooks.each { |hook| hook.execute(data) } +end+
# File app/roles/push_observer.rb, line 5 +def observe_push(oldrev, newrev, ref, user) + data = post_receive_data(oldrev, newrev, ref, user) + + Event.create( + project: self, + action: Event::Pushed, + data: data, + author_id: data[:user_id] + ) +end+
# File app/roles/push_observer.rb, line 44 +def post_receive_data(oldrev, newrev, ref, user) + + push_commits = commits_between(oldrev, newrev) + + # Total commits count + push_commits_count = push_commits.size + + # Get latest 20 commits ASC + push_commits_limited = push_commits.last(20) + + # Hash to be passed as post_receive_data + data = { + before: oldrev, + after: newrev, + ref: ref, + user_id: user.id, + user_name: user.name, + repository: { + name: name, + url: web_url, + description: description, + homepage: web_url, + }, + commits: [], + total_commits_count: push_commits_count + } + + # For perfomance purposes maximum 20 latest commits + # will be passed as post receive hook data. + # + push_commits_limited.each do |commit| + data[:commits] << { + id: commit.id, + message: commit.safe_message, + timestamp: commit.date.xmlschema, + url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}", + author: { + name: commit.author_name, + email: commit.author_email + } + } + end + + data +end+
This method will be called after each post receive and only if the provided +user is present in GitLab.
+ +All callbacks for post receive should be placed here.
+ + + +# File app/roles/push_observer.rb, line 94 +def trigger_post_receive(oldrev, newrev, ref, user) + # Create push event + self.observe_push(oldrev, newrev, ref, user) + + # Close merged MR + self.update_merge_requests(oldrev, newrev, ref, user) + + # Execute web hooks + self.execute_hooks(oldrev, newrev, ref, user) + + # Create satellite + self.satellite.create unless self.satellite.exists? + + # Discover the default branch, but only if it hasn't already been set to + # something else + if default_branch.nil? + update_attributes(default_branch: discover_default_branch) + end +end+
# File app/roles/push_observer.rb, line 16 +def update_merge_requests(oldrev, newrev, ref, user) + return true unless ref =~ %rheads/ + branch_name = ref.gsub("refs/heads/", "") + c_ids = self.commits_between(oldrev, newrev).map(&:id) + + # Update code for merge requests + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all + mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } + + # Close merge requests + mrs = self.merge_requests.opened.where(target_branch: branch_name).all + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) } + mrs.each { |merge_request| merge_request.merge!(user.id) } + + true +end+
Redcarpet::Render::HTML + +
# File lib/redcarpet/render/gitlab_html.rb, line 6 +def initialize(template, options = {}) + @template = template + @project = @template.instance_variable_get("@project") + super options +end+
# File lib/redcarpet/render/gitlab_html.rb, line 12 +def block_code(code, language) + if Pygments::Lexer.find(language) + Pygments.highlight(code, lexer: language, options: {encoding: 'utf-8'}) + else + Pygments.highlight(code, options: {encoding: 'utf-8'}) + end +end+
# File lib/redcarpet/render/gitlab_html.rb, line 20 +def postprocess(full_document) + h.gfm(full_document) +end+
# File app/controllers/refs_controller.rb, line 31 +def logs_tree + contents = @tree.contents + @logs = contents.map do |content| + file = params[:path] ? File.join(params[:path], content.name) : content.name + last_commit = @project.commits(@commit.id, file, 1).last + last_commit = CommitDecorator.decorate(last_commit) + { + file_name: content.name, + commit: last_commit + } + end +end+
# File app/controllers/refs_controller.rb, line 12 +def switch + respond_to do |format| + format.html do + new_path = if params[:destination] == "tree" + project_tree_path(@project, @ref) + else + project_commits_path(@project, @ref) + end + + redirect_to new_path + end + format.js do + @ref = params[:ref] + define_tree_vars + render "tree" + end + end +end+
# File app/controllers/refs_controller.rb, line 46 +def define_tree_vars + params[:path] = nil if params[:path].blank? + + @repo = project.repo + @commit = project.commit(@ref) + @commit = CommitDecorator.decorate(@commit) + @tree = Tree.new(@commit.tree, project, @ref, params[:path]) + @tree = TreeDecorator.new(@tree) + @hex_path = Digest::SHA1.hexdigest(params[:path] || "") + + if params[:path] + @logs_path = logs_file_project_ref_path(@project, @ref, params[:path]) + else + @logs_path = logs_tree_project_ref_path(@project, @ref) + end +rescue + return render_404 +end+
# File app/controllers/refs_controller.rb, line 65 +def ref + @ref = params[:id] || params[:ref] +end+
# File app/controllers/repositories_controller.rb, line 19 +def archive + unless can?(current_user, :download_code, @project) + render_404 and return + end + + + file_path = @project.archive_repo(params[:ref]) + + if file_path + # Send file to user + send_file file_path + else + render_404 + end +end+
# File app/controllers/repositories_controller.rb, line 11 +def branches + @branches = @project.branches +end+
# File app/controllers/repositories_controller.rb, line 7 +def show + @activities = @project.commits_with_refs(20) +end+
Archive Project to .tar.gz
+ +Already packed repo archives stored at +app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
+ + + +# File app/roles/repository.rb, line 157 +def archive_repo(ref) + ref = ref || self.root_ref + commit = self.commit(ref) + return nil unless commit + + # Build file path + file_name = self.code + "-" + commit.id.to_s + ".tar.gz" + storage_path = Rails.root.join("tmp", "repositories", self.code) + file_path = File.join(storage_path, file_name) + + # Put files into a directory before archiving + prefix = self.code + "/" + + # Create file if not exists + unless File.exists?(file_path) + FileUtils.mkdir_p storage_path + file = self.repo.archive_to_file(ref, prefix, file_path) + end + + file_path +end+
Returns an Array of branch names
+ + + +# File app/roles/repository.rb, line 53 +def branch_names + repo.branches.collect(&:name).sort +end+
Returns an Array of Branches
+ + + +# File app/roles/repository.rb, line 58 +def branches + repo.branches.sort_by(&:name) +end+
# File app/roles/repository.rb, line 15 +def commit(commit_id = nil) + Commit.find_or_first(repo, commit_id, root_ref) +end+
# File app/roles/repository.rb, line 31 +def commits(ref, path = nil, limit = nil, offset = nil) + Commit.commits(repo, ref, path, limit, offset) +end+
# File app/roles/repository.rb, line 39 +def commits_between(from, to) + Commit.commits_between(repo, from, to) +end+
# File app/roles/repository.rb, line 27 +def commits_since(date) + Commit.commits_since(repo, date) +end+
# File app/roles/repository.rb, line 23 +def commits_with_refs(n = 20) + Commit.commits_with_refs(repo, n) +end+
# File app/roles/repository.rb, line 93 +def destroy_repository + git_host.remove_repository(self) +end+
Discovers the default branch based on the repository’s available branches
+If no branches are present, returns nil
+If one branch is present, returns its name
+If two or more branches are present, returns the one that has a name +matching #root_ref +(default_branch or ‘master’ if default_branch is nil)
+# File app/roles/repository.rb, line 128 +def discover_default_branch + if branch_names.length == 0 + nil + elsif branch_names.length == 1 + branch_names.first + else + branch_names.select { |v| v == root_ref }.first + end +end+
# File app/roles/repository.rb, line 11 +def empty_repo? + !repo_exists? || !has_commits? +end+
# File app/roles/repository.rb, line 19 +def fresh_commits(n = 10) + Commit.fresh_commits(repo, n) +end+
# File app/roles/repository.rb, line 138 +def has_commits? + !!commit +rescue Grit::NoSuchPathError + false +end+
# File app/roles/repository.rb, line 47 +def has_post_receive_file? + hook_file = File.join(path_to_repo, 'hooks', 'post-receive') + File.exists?(hook_file) +end+
# File app/roles/repository.rb, line 103 +def heads + @heads ||= repo.heads +end+
# File app/roles/repository.rb, line 183 +def http_url_to_repo + http_url = [Gitlab.config.url, "/", path, ".git"].join('') +end+
# File app/roles/repository.rb, line 35 +def last_commit_for(ref, path = nil) + commits(ref, path, 1).first +end+
# File app/roles/repository.rb, line 113 +def open_branches + if protected_branches.empty? + self.repo.heads + else + pnames = protected_branches.map(&:name) + self.repo.heads.reject { |h| pnames.include?(h.name) } + end.sort_by(&:name) +end+
# File app/roles/repository.rb, line 85 +def path_to_repo + File.join(Gitlab.config.git_base_path, "#{path}.git") +end+
Check if current branch name is marked as protected in the system
+ + + +# File app/roles/repository.rb, line 188 +def protected_branch? branch_name + protected_branches.map(&:name).include?(branch_name) +end+
Returns an Array of branch and tag names
+ + + +# File app/roles/repository.rb, line 73 +def ref_names + [branch_names + tag_names].flatten +end+
# File app/roles/repository.rb, line 77 +def repo + @repo ||= Grit::Repo.new(path_to_repo) +end+
# File app/roles/repository.rb, line 97 +def repo_exists? + @repo_exists ||= (repo && !repo.branches.empty?) +rescue + @repo_exists = false +end+
# File app/roles/repository.rb, line 144 +def root_ref + default_branch || "master" +end+
# File app/roles/repository.rb, line 148 +def root_ref?(branch) + root_ref == branch +end+
# File app/roles/repository.rb, line 43 +def satellite + @satellite ||= Gitlab::Satellite.new(self) +end+
# File app/roles/repository.rb, line 179 +def ssh_url_to_repo + url_to_repo +end+
Returns an Array of tag names
+ + + +# File app/roles/repository.rb, line 63 +def tag_names + repo.tags.collect(&:name).sort.reverse +end+
# File app/roles/repository.rb, line 107 +def tree(fcommit, path = nil) + fcommit = commit if fcommit == :head + tree = fcommit.tree + path ? (tree / path) : tree +end+
# File app/roles/repository.rb, line 89 +def update_repository + git_host.update_repository(self) +end+
# File app/roles/repository.rb, line 81 +def url_to_repo + git_host.url_to_repo(path) +end+
# File app/roles/repository.rb, line 4 +def valid_repo? + repo +rescue + errors.add(:path, "Invalid repository path") + false +end+
# File app/contexts/search_context.rb, line 4 +def initialize(project_ids, params) + @project_ids, @params = project_ids, params.dup +end+
# File app/contexts/search_context.rb, line 8 +def execute + query = params[:search] + + return result unless query.present? + + result[:projects] = Project.where(id: project_ids).search(query).limit(10) + result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10) + result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) + result +end+
# File app/contexts/search_context.rb, line 19 +def result + @result ||= { + projects: [], + merge_requests: [], + issues: [] + } +end+
# File app/controllers/search_controller.rb, line 2 +def show + result = SearchContext.new(current_user.project_ids, params).execute + + @projects = result[:projects] + @merge_requests = result[:merge_requests] + @issues = result[:issues] +end+
ActiveRecord::Base + +
# File app/models/snippet.rb, line 23 +def self.content_types + [ + ".rb", ".py", ".pl", ".scala", ".c", ".cpp", ".java", + ".haml", ".html", ".sass", ".scss", ".xml", ".php", ".erb", + ".js", ".sh", ".coffee", ".yml", ".md" + ] +end+
# File app/models/snippet.rb, line 31 +def data + content +end+
# File app/models/snippet.rb, line 47 +def expired? + expires_at && expires_at < Time.current +end+
# File app/models/snippet.rb, line 43 +def mode + nil +end+
# File app/models/snippet.rb, line 39 +def name + file_name +end+
# File app/models/snippet.rb, line 35 +def size + 0 +end+
# File app/controllers/snippets_controller.rb, line 26 +def create + @snippet = @project.snippets.new(params[:snippet]) + @snippet.author = current_user + @snippet.save + + if @snippet.valid? + redirect_to [@project, @snippet] + else + respond_with(@snippet) + end +end+
# File app/controllers/snippets_controller.rb, line 55 +def destroy + return access_denied! unless can?(current_user, :admin_snippet, @snippet) + + @snippet.destroy + + redirect_to project_snippets_path(@project) +end+
# File app/controllers/snippets_controller.rb, line 38 +def edit +end+
# File app/controllers/snippets_controller.rb, line 18 +def index + @snippets = @project.snippets +end+
# File app/controllers/snippets_controller.rb, line 22 +def new + @snippet = @project.snippets.new +end+
# File app/controllers/snippets_controller.rb, line 63 +def raw + send_data( + @snippet.content, + type: "text/plain", + disposition: 'inline', + filename: @snippet.file_name + ) +end+
# File app/controllers/snippets_controller.rb, line 51 +def show + @note = @project.notes.new(noteable: @snippet) +end+
# File app/controllers/snippets_controller.rb, line 41 +def update + @snippet.update_attributes(params[:snippet]) + + if @snippet.valid? + redirect_to [@project, @snippet] + else + respond_with(@snippet) + end +end+
# File app/controllers/snippets_controller.rb, line 74 +def snippet + @snippet ||= @project.snippets.find(params[:id]) +end+
# File app/helpers/snippets_helper.rb, line 2 +def lifetime_select_options + options = [ + ['forever', nil], + ['1 day', "#{Date.current + 1.day}"], + ['1 week', "#{Date.current + 1.week}"], + ['1 month', "#{Date.current + 1.month}"] + ] + options_for_select(options) +end+
Provides an ActiveRecord-like interface to a model whose data is not +persisted to a database.
+ +# File app/roles/static_model.rb, line 40 +def ==(other) + if other.is_a? StaticModel + id == other.id + else + super + end +end+
Used by AR for fetching attributes
+ +Pass it along if we respond to it.
+ + + +# File app/roles/static_model.rb, line 20 +def [](key) + send(key) if respond_to?(key) +end+
# File app/roles/static_model.rb, line 36 +def destroyed? + false +end+
# File app/roles/static_model.rb, line 28 +def new_record? + false +end+
# File app/roles/static_model.rb, line 32 +def persisted? + false +end+
# File app/roles/static_model.rb, line 24 +def to_param + id +end+
Used by ActiveRecord’s polymorphic association to set object_type
+ + + +# File app/roles/static_model.rb, line 12 +def base_class + self +end+
Used by ActiveRecord’s polymorphic association to set object_id
+ + + +# File app/roles/static_model.rb, line 7 +def primary_key + 'id' +end+
WebHook + +
# File app/models/system_hook.rb, line 2 +def self.all_hooks_fire(data) + SystemHook.all.each do |sh| + sh.async_execute data + end +end+
# File app/models/system_hook.rb, line 8 +def async_execute(data) + Resque.enqueue(SystemHookWorker, id, data) +end+
ActiveRecord::Observer + +
# File app/observers/system_hook_observer.rb, line 4 +def after_create(model) + if model.kind_of? Project + SystemHook.all_hooks_fire({ + event_name: "project_create", + name: model.name, + path: model.path, + project_id: model.id, + owner_name: model.owner.name, + owner_email: model.owner.email, + created_at: model.created_at + }) + elsif model.kind_of? User + SystemHook.all_hooks_fire({ + event_name: "user_create", + name: model.name, + email: model.email, + created_at: model.created_at + }) + + elsif model.kind_of? UsersProject + SystemHook.all_hooks_fire({ + event_name: "user_add_to_team", + project_name: model.project.name, + project_path: model.project.path, + project_id: model.project_id, + user_name: model.user.name, + user_email: model.user.email, + project_access: model.repo_access_human, + created_at: model.created_at + }) + + end +end+
# File app/observers/system_hook_observer.rb, line 38 +def after_destroy(model) + if model.kind_of? Project + SystemHook.all_hooks_fire({ + event_name: "project_destroy", + name: model.name, + path: model.path, + project_id: model.id, + owner_name: model.owner.name, + owner_email: model.owner.email, + }) + elsif model.kind_of? User + SystemHook.all_hooks_fire({ + event_name: "user_destroy", + name: model.name, + email: model.email + }) + + elsif model.kind_of? UsersProject + SystemHook.all_hooks_fire({ + event_name: "user_remove_from_team", + project_name: model.project.name, + project_path: model.project.path, + project_id: model.project_id, + user_name: model.user.name, + user_email: model.user.email, + project_access: model.repo_access_human + }) + end +end+
Object + +
# File app/workers/system_hook_worker.rb, line 4 +def self.perform(hook_id, data) + SystemHook.find(hook_id).execute data +end+
# File app/helpers/tab_helper.rb, line 80 +def branches_tab_class + if current_page?(branches_project_repository_path(@project)) || + current_controller?(:protected_branches) || + current_page?(project_repository_path(@project)) + 'active' + end +end+
# File app/helpers/tab_helper.rb, line 70 +def project_tab_class + [:show, :files, :edit, :update].each do |action| + return "active" if current_page?(controller: "projects", action: action, id: @project) + end + + if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name + "active" + end +end+
# File app/helpers/tags_helper.rb, line 6 +def tag_list project + html = '' + project.tag_list.each do |tag| + html += link_to tag, tag_path(tag) + end + + html.html_safe +end+
# File app/helpers/tags_helper.rb, line 2 +def tag_path tag + "/tags/#{tag}" +end+
Add user to project with passed access role by user id
+ + + +# File app/roles/team.rb, line 26 +def add_user_id_to_team(user_id, access_role) + users_projects.create( + user_id: user_id, + project_access: access_role + ) +end+
Add user to project with passed access role
+ + + +# File app/roles/team.rb, line 14 +def add_user_to_team(user, access_role) + add_user_id_to_team(user.id, access_role) +end+
Add multiple users to project with same access role by user ids
+ + + +# File app/roles/team.rb, line 35 +def add_users_ids_to_team(users_ids, access_role) + UsersProject.bulk_import(self, users_ids, access_role) + self.update_repository +end+
Add multiple users to project with same access role
+ + + +# File app/roles/team.rb, line 20 +def add_users_to_team(users, access_role) + add_users_ids_to_team(users.map(&:id), access_role) +end+
Delete multiple users from project by user ids
+ + + +# File app/roles/team.rb, line 48 +def delete_users_ids_from_team(users_ids) + UsersProject.bulk_delete(self, users_ids) + self.update_repository +end+
Get Team Member record by user id
+ + + +# File app/roles/team.rb, line 8 +def team_member_by_id(user_id) + users_projects.find_by_user_id(user_id) +end+
# File app/roles/team.rb, line 2 +def team_member_by_name_or_email(name = nil, email = nil) + user = users.where("name like ? or email like ?", name, email).first + users_projects.where(user: user) if user +end+
Update multiple project users to same access role by user ids
+ + + +# File app/roles/team.rb, line 42 +def update_users_ids_to_role(users_ids, access_role) + UsersProject.bulk_update(self, users_ids, access_role) + self.update_repository +end+
# File app/controllers/team_members_controller.rb, line 47 +def apply_import + giver = Project.find(params[:source_project_id]) + status = UsersProject.import_team(giver, project) + notice = status ? "Succesfully imported" : "Import failed" + + redirect_to project_team_members_path(project), notice: notice +end+
# File app/controllers/team_members_controller.rb, line 18 +def create + @project.add_users_ids_to_team( + params[:user_ids], + params[:project_access] + ) + + redirect_to project_team_index_path(@project) +end+
# File app/controllers/team_members_controller.rb, line 37 +def destroy + @team_member = project.users_projects.find(params[:id]) + @team_member.destroy + + respond_to do |format| + format.html { redirect_to project_team_index_path(@project) } + format.js { render nothing: true } + end +end+
# File app/controllers/team_members_controller.rb, line 6 +def index +end+
# File app/controllers/team_members_controller.rb, line 14 +def new + @team_member = project.users_projects.new +end+
# File app/controllers/team_members_controller.rb, line 9 +def show + @team_member = project.users_projects.find(params[:id]) + @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7) +end+
# File app/controllers/team_members_controller.rb, line 27 +def update + @team_member = project.users_projects.find(params[:id]) + @team_member.update_attributes(params[:team_member]) + + unless @team_member.valid? + flash[:alert] = "User should have at least one role" + end + redirect_to project_team_index_path(@project) +end+
BaseContext + +
# File app/contexts/test_hook_context.rb, line 2 +def execute + hook = project.hooks.find(params[:id]) + commits = project.commits(project.default_branch, nil, 3) + data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + hook.execute(data) +end+
Object + +
# File app/models/tree.rb, line 8 +def initialize(raw_tree, project, ref = nil, path = nil) + @project, @ref, @path = project, ref, path + @tree = if path.present? + raw_tree / path.dup.force_encoding('ascii-8bit') + else + raw_tree + end +end+
# File app/models/tree.rb, line 25 +def empty? + data.blank? +end+
# File app/models/tree.rb, line 21 +def invalid? + tree.nil? +end+
# File app/models/tree.rb, line 17 +def is_blob? + tree.is_a?(Grit::Blob) +end+
Controller for viewing a repository’s file structure
+ +# File app/controllers/tree_controller.rb, line 24 +def edit + @last_commit = @project.last_commit_for(@ref, @path).sha +end+
# File app/controllers/tree_controller.rb, line 13 +def show + @hex_path = Digest::SHA1.hexdigest(@path) + @logs_path = logs_file_project_ref_path(@project, @ref, @path) + + respond_to do |format| + format.html + # Disable cache so browser history works + format.js { no_cache_headers } + end +end+
# File app/controllers/tree_controller.rb, line 28 +def update + file_editor = Gitlab::FileEditor.new(current_user, @project, @ref) + update_status = file_editor.update( + @path, + params[:content], + params[:commit_message], + params[:last_commit] + ) + + if update_status + redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited" + else + flash[:notice] = "Your changes could not be commited, because the file has been changed" + render :edit + end +end+
# File app/decorators/tree_decorator.rb, line 32 +def readme + @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ %r^readme/ } +end+
# File app/decorators/tree_decorator.rb, line 23 +def up_dir? + path.present? +end+
# File app/decorators/tree_decorator.rb, line 27 +def up_dir_path + file = File.join(path, "..") + h.project_tree_path(project, h.tree_join(ref, file)) +end+
# File app/helpers/tree_helper.rb, line 63 +def allowed_tree_edit? + if @project.protected_branch? @ref + can?(current_user, :push_code_to_protected_branches, @project) + else + can?(current_user, :push_code, @project) + end +end+
# File app/helpers/tree_helper.rb, line 50 +def gitlab_markdown?(filename) + filename.end_with?(*%w(.mdown .md .markdown)) +end+
Public: Determines if a given filename is compatible with GitHub::Markup.
+ +filename - Filename string to check
+ +Returns boolean
+ + + +# File app/helpers/tree_helper.rb, line 45 +def markup?(filename) + filename.end_with?(*%w(.textile .rdoc .org .creole + .mediawiki .rst .asciidoc .pod)) +end+
# File app/helpers/tree_helper.rb, line 54 +def plain_text_readme? filename + filename == 'README' +end+
Sorts a repository’s tree so that folders are before files and renders +their corresponding partials
+ +contents - A Grit::Tree object for the current tree
+ + + +# File app/helpers/tree_helper.rb, line 6 +def render_tree(contents) + # Render Folders before Files/Submodules + folders, files = contents.partition { |v| v.kind_of?(Grit::Tree) } + + tree = "" + + # Render folders if we have any + tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? + + files.each do |f| + if f.respond_to?(:url) + # Object is a Submodule + tree += render partial: 'tree/submodule_item', object: f + else + # Object is a Blob + tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'} + end + end + + tree.html_safe +end+
# File app/helpers/tree_helper.rb, line 36 +def tree_hex_class(content) + "file_#{hexdigest(content.name)}" +end+
Return an image icon depending on the file type
+ +type - String type of the tree item; either ‘folder’ or ‘file’
+ + + +# File app/helpers/tree_helper.rb, line 31 +def tree_icon(type) + image = type == 'folder' ? 'file_dir.png' : 'file_txt.png' + image_tag(image, size: '16x16') +end+
Simple shortcut to File.join
+ + + +# File app/helpers/tree_helper.rb, line 59 +def tree_join(*args) + File.join(*args) +end+
ActiveRecord::Base + +
# File app/models/user.rb, line 55 +def create_from_omniauth(auth, ldap = false) + gitlab_auth.create_from_omniauth(auth, ldap) +end+
# File app/models/user.rb, line 41 +def filter filter_name + case filter_name + when "admins"; self.admins + when "blocked"; self.blocked + when "wop"; self.without_projects + else + self.active + end +end+
# File app/models/user.rb, line 63 +def find_for_ldap_auth(auth, signed_in_resource = nil) + gitlab_auth.find_for_ldap_auth(auth, signed_in_resource) +end+
# File app/models/user.rb, line 59 +def find_or_new_for_omniauth(auth) + gitlab_auth.find_or_new_for_omniauth(auth) +end+
# File app/models/user.rb, line 67 +def gitlab_auth + Gitlab::Auth.new +end+
# File app/models/user.rb, line 71 +def search query + where("name LIKE :query or email LIKE :query", query: "%#{query}%") +end+
# File app/models/user.rb, line 51 +def without_projects + where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') +end+
# File app/models/user.rb, line 76 +def generate_password + if self.force_random_password + self.password = self.password_confirmation = Devise.friendly_token.first(8) + end +end+
ActiveRecord::Observer + +
# File app/observers/user_observer.rb, line 2 +def after_create(user) + log_info("User \"#{user.name}\" (#{user.email}) was created") + + Notify.new_user_email(user.id, user.password).deliver +end+
# File app/observers/user_observer.rb, line 8 +def after_destroy user + log_info("User \"#{user.name}\" (#{user.email}) was removed") +end+
# File app/observers/user_observer.rb, line 14 +def log_info message + Gitlab::AppLogger.info message +end+
ActiveRecord::Base + +
# File app/models/users_project.rb, line 96 +def access_roles + { + "Guest" => GUEST, + "Reporter" => REPORTER, + "Developer" => DEVELOPER, + "Master" => MASTER + } +end+
# File app/models/users_project.rb, line 53 +def bulk_delete(project, user_ids) + UsersProject.transaction do + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| + users_project.destroy + end + end +end+
# File app/models/users_project.rb, line 70 +def bulk_import(project, user_ids, project_access) + UsersProject.transaction do + user_ids.each do |user_id| + users_project = UsersProject.new( + project_access: project_access, + user_id: user_id + ) + users_project.project = project + users_project.save + end + end +end+
# File app/models/users_project.rb, line 61 +def bulk_update(project, user_ids, project_access) + UsersProject.transaction do + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| + users_project.project_access = project_access + users_project.save + end + end +end+
# File app/models/users_project.rb, line 24 +def import_team(source_project, target_project) + UsersProject.without_repository_callback do + UsersProject.transaction do + team = source_project.users_projects.all + + team.each do |tm| + # Skip if user already present in team + next if target_project.users.include?(tm.user) + + new_tm = tm.dup + new_tm.id = nil + new_tm.project_id = target_project.id + new_tm.save + end + end + end + + target_project.update_repository + true +rescue + false +end+
# File app/models/users_project.rb, line 83 +def user_bulk_import(user, project_ids, project_access) + UsersProject.transaction do + project_ids.each do |project_id| + users_project = UsersProject.new( + project_access: project_access, + ) + users_project.project_id = project_id + users_project.user_id = user.id + users_project.save + end + end +end+
# File app/models/users_project.rb, line 47 +def without_repository_callback + UsersProject.skip_callback(:destroy, :after, :update_repository) + yield + UsersProject.set_callback(:destroy, :after, :update_repository) +end+
# File app/models/users_project.rb, line 114 +def project_access_human + Project.access_options.key(self.project_access) +end+
# File app/models/users_project.rb, line 118 +def repo_access_human + self.class.access_roles.invert[self.project_access] +end+
# File app/models/users_project.rb, line 106 +def role_access + project_access +end+
# File app/models/users_project.rb, line 110 +def update_repository + git_host.update_repository(project) +end+
ActiveRecord::Observer + +
# File app/observers/users_project_observer.rb, line 2 +def after_commit(users_project) + return if users_project.destroyed? + Notify.project_access_granted_email(users_project.id).deliver +end+
# File app/observers/users_project_observer.rb, line 7 +def after_create(users_project) + Event.create( + project_id: users_project.project.id, + action: Event::Joined, + author_id: users_project.user.id + ) +end+
# File app/observers/users_project_observer.rb, line 15 +def after_destroy(users_project) + Event.create( + project_id: users_project.project.id, + action: Event::Left, + author_id: users_project.user.id + ) +end+
Return the number of -1 comments (downvotes)
+ + + +# File app/roles/votes.rb, line 16 +def downvotes + notes.select(&:downvote?).size +end+
# File app/roles/votes.rb, line 20 +def downvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 - upvotes_in_percent + end +end+
Return the number of +1 comments (upvotes)
+ + + +# File app/roles/votes.rb, line 3 +def upvotes + notes.select(&:upvote?).size +end+
# File app/roles/votes.rb, line 7 +def upvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 / votes_count * upvotes + end +end+
Return the total number of votes
+ + + +# File app/roles/votes.rb, line 29 +def votes_count + upvotes + downvotes +end+
ActiveRecord::Base + +
# File app/models/web_hook.rb, line 12 +def execute(data) + parsed_url = URI.parse(url) + if parsed_url.userinfo.blank? + WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) + else + post_url = url.gsub("#{parsed_url.userinfo}@", "") + WebHook.post(post_url, + body: data.to_json, + headers: {"Content-Type" => "application/json"}, + basic_auth: {username: parsed_url.user, password: parsed_url.password}) + end +end+
ActiveRecord::Base + +
# File app/models/wiki.rb, line 20 +def self.regenerate_from wiki + regenerated_field = [:slug, :content, :title] + + new_wiki = Wiki.new + regenerated_field.each do |field| + new_wiki.send("#{field}=", wiki.send(field)) + end + new_wiki +end+
# File app/models/wiki.rb, line 14 +def to_param + slug +end+
# File app/models/wiki.rb, line 30 +def set_slug + self.slug = self.title.parameterize +end+
# File app/controllers/wikis_controller.rb, line 36 +def create + @wiki = @project.wikis.new(params[:wiki]) + @wiki.user = current_user + + respond_to do |format| + if @wiki.save + format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' } + else + format.html { render action: "edit" } + end + end +end+
# File app/controllers/wikis_controller.rb, line 53 +def destroy + @wikis = @project.wikis.where(slug: params[:id]).delete_all + + respond_to do |format| + format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" } + end +end+
# File app/controllers/wikis_controller.rb, line 31 +def edit + @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last + @wiki = Wiki.regenerate_from @wiki +end+
# File app/controllers/wikis_controller.rb, line 49 +def history + @wikis = @project.wikis.where(slug: params[:id]).order("created_at") +end+
# File app/controllers/wikis_controller.rb, line 6 +def pages + @wikis = @project.wikis.group(:slug).order("created_at") +end+
# File app/controllers/wikis_controller.rb, line 10 +def show + if params[:old_page_id] + @wiki = @project.wikis.find(params[:old_page_id]) + else + @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last + end + + @note = @project.notes.new(noteable: @wiki) + + if @wiki + render 'show' + else + if can?(current_user, :write_wiki, @project) + @wiki = @project.wikis.new(slug: params[:id]) + render 'edit' + else + render 'empty' + end + end +end+
Use this README file to introduce your application and point to useful +places in the API for learning more. Run “rake doc:app” to generate API +documentation for your models, controllers, helpers, and libraries.
+ +This is the API documentation for Rails Application Documentation.
+
+
+
+
diff --git a/doc/app/js/darkfish.js b/doc/app/js/darkfish.js
new file mode 100644
index 00000000..4be722fa
--- /dev/null
+++ b/doc/app/js/darkfish.js
@@ -0,0 +1,153 @@
+/**
+ *
+ * Darkfish Page Functions
+ * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
+ *
+ * Author: Michael Granger Table of Contents - Rails Application Documentation
+
+Pages
+
+
+
+Classes/Modules
+
+
+
+Methods
+
+
+
+
+
+
+