- 2.0.0
services:
- mysql
+ - redis-server
before_script:
- "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml"
+v 6.4.0
+ - Added sorting to project issues page (Jason Blanchard)
+ - Assembla integration (Carlos Paramio)
+ - Fixed another 500 error with submodules
+ - UI: More compact issues page
+ - Minimal password length increased to 8 symbols
+
v 6.3.0
- API for adding gitlab-ci service
- Init script now waits for pids to appear after (re)starting before reporting status (Rovanion Luckey)
- Fixed issue with 500 error when group did not exist
- Ability to leave project
- You can create file in repo using UI
+ - You can remove file from repo using UI
- API: dropped default_branch attribute from project during creation
- Project default_branch is not stored in db any more. It takes from repo now.
- Admin broadcast messages
- Dont show last push widget if user removed this branch
- Fix 500 error for repos with newline in file name
- Extended html titles
- - API: create/update repo files
+ - API: create/update/delete repo files
- Admin can transfer project to any namespace
+ - API: projects/all for admin users
+ - Fix recent branches order
+
+v 6.2.4
+ - Security: Cast API private_token to string (CVE-2013-4580)
+ - Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
+ - Fix for Git SSH access for LDAP users
+
+v 6.2.3
+ - Security: More protection against CVE-2013-4489
+ - Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
+ - Fix sidekiq rake tasks
+
+v 6.2.2
+ - Security: Update gitlab_git (CVE-2013-4489)
+
+v 6.2.1
+ - Security: Fix issue with generated passwords for new users
v 6.2.0
- Public project pages are now visible to everyone (files, issues, wik, etc.)
- Improved MR comments logic
- Render readme file for projects in public area
+v 5.4.2
+ - Security: Cast API private_token to string (CVE-2013-4580)
+ - Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
+
+v 5.4.1
+ - Security: Fixes for CVE-2013-4489
+ - Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
+
v 5.4.0
- Ability to edit own comments
- Documentation improvements
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", "~> 3.0.0.rc2"
+gem "gitlab_git", "~> 3.1.0"
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
# Syntax highlighter
-gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
+gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
# Git Wiki
-gem "gitlab-gollum-lib", "~> 1.0.1", require: 'gollum-lib'
+gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib'
# Language detection
-gem "github-linguist", require: "linguist"
+gem "gitlab-linguist", "~> 2.9.6", require: "linguist"
# API
gem "grape", "~> 0.4.1"
gem 'turbolinks'
gem 'jquery-turbolinks'
- gem 'chosen-rails', "1.0.0"
+ gem 'chosen-rails', "1.0.1"
gem 'select2-rails'
gem 'jquery-atwho-rails', "0.3.0"
gem "jquery-rails", "2.1.3"
charlock_holmes (0.6.9.4)
childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11)
- chosen-rails (1.0.0)
+ chosen-rails (1.0.1)
coffee-rails (>= 3.2)
compass-rails (>= 1.0)
railties (>= 3.0)
sass-rails (>= 3.2)
- chunky_png (1.2.8)
+ chunky_png (1.2.9)
cliver (0.2.1)
code_analyzer (0.4.3)
sexp_processor
coffee-script (2.2.0)
coffee-script-source
execjs
- coffee-script-source (1.6.2)
+ coffee-script-source (1.6.3)
colored (1.2)
colorize (0.5.8)
compass (0.12.2)
escape_utils (0.2.4)
eventmachine (1.0.3)
excon (0.13.4)
- execjs (1.4.0)
- multi_json (~> 1.0)
+ execjs (2.0.2)
factory_girl (4.2.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.2.1)
fssm (0.2.10)
gemoji (1.2.1)
gherkin-ruby (0.3.0)
- github-linguist (2.3.4)
- charlock_holmes (~> 0.6.6)
- escape_utils (~> 0.2.3)
- mime-types (~> 1.19)
- pygments.rb (>= 0.2.13)
- github-markdown (0.5.3)
+ github-markdown (0.5.5)
github-markup (0.7.5)
gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1)
multi_json
- gitlab-gollum-lib (1.0.1)
+ gitlab-gollum-lib (1.0.2)
github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0)
- gitlab-grit (>= 2.5.1)
+ gitlab-grit (~> 2.6.1)
+ gitlab-pygments.rb (~> 0.5.4)
nokogiri (~> 1.5.9)
- pygments.rb (~> 0.4.2)
sanitize (~> 2.0.3)
stringex (~> 1.5.1)
gitlab-grack (1.0.1)
rack (~> 1.4.1)
- gitlab-grit (2.6.2)
+ gitlab-grit (2.6.3)
charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
- gitlab-pygments.rb (0.3.2)
+ gitlab-linguist (2.9.6)
+ charlock_holmes (~> 0.6.6)
+ escape_utils (~> 0.2.4)
+ gitlab-pygments.rb (~> 0.5.4)
+ mime-types (~> 1.19)
+ gitlab-pygments.rb (0.5.4)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
- gitlab_git (3.0.0.rc2)
+ gitlab_git (3.1.0)
activesupport (~> 3.2.13)
- github-linguist (~> 2.3.4)
gitlab-grit (~> 2.6.1)
+ gitlab-linguist (~> 2.9.5)
+ gitlab-pygments.rb (~> 0.5.4)
gitlab_meta (6.0)
gitlab_omniauth-ldap (1.0.3)
net-ldap (~> 0.3.1)
mime-types (~> 1.16)
treetop (~> 1.4.8)
method_source (0.8.1)
- mime-types (1.25)
+ mime-types (1.25.1)
minitest (4.7.4)
modernizr (2.6.2)
sprockets (~> 2.0)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
- pygments.rb (0.4.2)
- posix-spawn (~> 0.3.6)
- yajl-ruby (~> 1.1.0)
pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
safe_yaml (0.9.3)
sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6)
- sass (3.2.11)
+ sass (3.2.12)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
bootstrap-sass
capybara
carrierwave
- chosen-rails (= 1.0.0)
+ chosen-rails (= 1.0.1)
coffee-rails
colored
coveralls
font-awesome-rails
foreman
gemoji (~> 1.2.1)
- github-linguist
github-markup (~> 0.7.4)
gitlab-flowdock-git-hook (~> 0.4.2)
- gitlab-gollum-lib (~> 1.0.1)
+ gitlab-gollum-lib (~> 1.0.2)
gitlab-grack (~> 1.0.1)
- gitlab-pygments.rb (~> 0.3.2)
- gitlab_git (~> 3.0.0.rc2)
+ gitlab-linguist (~> 2.9.6)
+ gitlab-pygments.rb (~> 0.5.4)
+ gitlab_git (~> 3.1.0)
gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3)
gon
/** COLORS **/
.cgray { color: gray }
+.clgray { color: #BBB }
.cred { color: #D12F19 }
.cgreen { color: #4a2 }
.cblue { color: #29A }
font-size: 12px;
font-style: normal;
font-weight: normal;
+
+ &.label-gray {
+ background-color: #eee;
+ color: #999;
+ text-shadow: none;
+ }
}
/** Big Labels **/
.dropdown-menu > li > a {
text-shadow: none;
}
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background: #29b;
+}
label {
@extend .control-label;
+
+ &.radio-label {
+ text-align: left;
+ width: 100%;
+ margin-left: 0;
+
+ input[type="radio"] {
+ margin-top: 1px !important;
+ }
+ }
}
}
@media (min-width: 800px) { .issues_filters select { width: 160px; } }
@media (min-width: 1200px) { .issues_filters select { width: 220px; } }
-@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } }
-@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } }
+@media (min-width: 800px) { .issues_bulk_update .chosen-container { min-width: 120px; } }
+@media (min-width: 1200px) { .issues_bulk_update .chosen-container { min-width: 160px; } }
.issues-holder {
.issues_filters {
.participants {
margin-bottom: 10px;
}
+
+.issues_bulk_update {
+ .chosen-container {
+ text-shadow: none;
+ }
+}
+
+.issue-search-form {
+ margin: 0;
+ height: 24px;
+
+ .issue_search {
+ border: 1px solid #DDD !important;
+ background-color: #f4f4f4;
+ }
+}
return error("You can only create files if you are on top of a branch")
end
- file_name = params[:file_name]
+ file_name = File.basename(path)
+ file_path = path
unless file_name =~ Gitlab::Regex.path_regex
return error("Your changes could not be commited, because file name contains not allowed characters")
end
- file_path = if path.blank?
- file_name
- else
- File.join(path, file_name)
- end
-
blob = repository.blob_at(ref, file_path)
if blob
--- /dev/null
+module Files
+ class DeleteContext < BaseContext
+ def execute
+ allowed = if project.protected_branch?(ref)
+ can?(current_user, :push_code_to_protected_branches, project)
+ else
+ can?(current_user, :push_code, project)
+ end
+
+ unless allowed
+ return error("You are not allowed to push into this branch")
+ end
+
+ unless repository.branch_names.include?(ref)
+ return error("You can only create files if you are on top of a branch")
+ end
+
+ blob = repository.blob_at(ref, path)
+
+ unless blob
+ return error("You can only edit text files")
+ end
+
+ delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path)
+
+ deleted_successfully = delete_file_action.commit!(
+ nil,
+ params[:commit_message]
+ )
+
+ if deleted_successfully
+ success
+ else
+ error("Your changes could not be commited, because the file has been changed")
+ end
+ end
+ end
+end
if params[:milestone_id].present?
@issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
end
+
+ # Sort by :sort param
+ @issues = sort(@issues, params[:sort])
@issues
end
+
+ private
+
+ def sort(issues, condition)
+ case condition
+ when 'newest' then issues.except(:order).order('created_at DESC')
+ when 'oldest' then issues.except(:order).order('created_at ASC')
+ when 'recently_updated' then issues.except(:order).order('updated_at DESC')
+ when 'last_updated' then issues.except(:order).order('updated_at ASC')
+ when 'milestone_due_soon' then issues.except(:order).joins(:milestone).order("milestones.due_date ASC")
+ when 'milestone_due_later' then issues.except(:order).joins(:milestone).order("milestones.due_date DESC")
+ else issues
+ end
+ end
+
end
end
def index
@projects = Project.order("created_at DESC").limit(10)
@users = User.order("created_at DESC").limit(10)
+ @groups = Group.order("created_at DESC").limit(10)
end
end
before_filter :authorize_code_access!
before_filter :require_non_empty_project
+ before_filter :blob
+
def show
- @blob = @repository.blob_at(@commit.id, @path)
+ end
+
+ def destroy
+ result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute
+
+ if result[:status] == :success
+ flash[:notice] = "Your changes have been successfully commited"
+ redirect_to project_tree_path(@project, @ref)
+ else
+ flash[:alert] = result[:error]
+ render :show
+ end
+ end
+
+ private
+
+ def blob
+ @blob ||= @repository.blob_at(@commit.id, @path)
+
+ return not_found! unless @blob
- not_found! unless @blob
+ @blob
end
end
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
+ sort_param = params[:sort] || 'newest'
+ @sort = sort_param.humanize unless sort_param.empty?
+
respond_to do |format|
format.html # index.html.erb
end
def update
- result = Files::CreateContext.new(@project, current_user, params, @ref, @path).execute
+ file_path = File.join(@path, File.basename(params[:file_name]))
+ result = Files::CreateContext.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully commited"
- redirect_to project_blob_path(@project, File.join(@id, params[:file_name]))
+ redirect_to project_blob_path(@project, File.join(@ref, file_path))
else
flash[:alert] = result[:error]
render :show
Gitlab.config.extra
end
- def public_icon
- content_tag :i, nil, class: 'icon-globe cblue'
- end
-
- def private_icon
- content_tag :i, nil, class: 'icon-lock cgreen'
- end
-
def search_placeholder
if @project && @project.persisted?
"Search in this project"
source_name
end
- user = User.where('name like ? or email like ?', source_name, source_email).first
+ # Prefer email match over name match
+ user = User.where(email: source_email).first
+ user ||= User.where(name: source_name).first
options = {
class: "commit-#{options[:source]}-link has_tooltip",
end
elsif event.note_project_snippet?
link_to(project_snippet_path(event.project, event.note_target)) do
- content_tag :strong do
- "#{event.note_target_type} ##{truncate event.note_target_id}"
- end
+ "#{event.note_target_type} ##{truncate event.note_target_id}"
end
else
link_to event_note_target_path(event) do
- content_tag :strong do
- "#{event.note_target_type} ##{truncate event.note_target_iid}"
- end
+ "#{event.note_target_type} ##{truncate event.note_target_iid}"
end
end
elsif event.wall_note?
--- /dev/null
+module IconsHelper
+ def boolean_to_icon(value)
+ if value.to_s == "true"
+ content_tag :i, nil, class: 'icon-ok cgreen'
+ else
+ content_tag :i, nil, class: 'icon-off clgray'
+ end
+ end
+
+ def public_icon
+ content_tag :i, nil, class: 'icon-globe cblue'
+ end
+
+ def private_icon
+ content_tag :i, nil, class: 'icon-lock cgreen'
+ end
+end
false
end
end
+
+ def bulk_update_milestone_options
+ options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
+ end
+
+ def bulk_update_assignee_options
+ options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
+ end
end
scope: params[:scope],
label_name: params[:label_name],
milestone_id: params[:milestone_id],
+ assignee_id: params[:assignee_id],
+ sort: params[:sort],
}
options = exist_opts.merge(options)
--- /dev/null
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# token :string(255)
+# project_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean default(FALSE), not null
+# project_url :string(255)
+# subdomain :string(255)
+# room :string(255)
+#
+
+class AssemblaService < Service
+ include HTTParty
+
+ validates :token, presence: true, if: :activated?
+
+ def title
+ 'Assembla'
+ end
+
+ def description
+ 'Project Management Software (Source Commits Endpoint)'
+ end
+
+ def to_param
+ 'assembla'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'token', placeholder: '' }
+ ]
+ end
+
+ def execute(push)
+ url = "https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=#{token}"
+ AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' })
+ end
+end
# Max 20 commits from push DESC
def commits
- @commits ||= data[:commits].reverse
+ @commits ||= (data[:commits] || []).reverse
end
def commits_count
end
def description
- 'Simple web-based real-time group chat'
+ 'Private group chat and IM'
end
def to_param
has_one :pivotaltracker_service, dependent: :destroy
has_one :hipchat_service, dependent: :destroy
has_one :flowdock_service, dependent: :destroy
+ has_one :assembla_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla)
end
def gitlab_ci?
raise TransferError.new("Project with same path in target namespace already exists")
end
+ # Remove old satellite
+ project.satellite.destroy
+
+ # Apply new namespace id
project.namespace = new_namespace
project.save!
# Move wiki repo also if present
gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki")
- # create satellite repo
- project.ensure_satellite_exists
+ # Create a new satellite (reload project from DB)
+ Project.find(project.id).ensure_satellite_exists
# clear project cached events
project.reset_events_cache
ago
.span4
+ %h4 Latest groups
+ %hr
+ - @groups.each do |group|
+ %p
+ = link_to [:admin, group] do
+ = group.name
+ %span.light.pull-right
+ = time_ago_in_words group.created_at
+ ago
+
+%br
+.row
+ .span4
%h4 Stats
%hr
%p
Milestones
%span.light.pull-right
= Milestone.count
+ .span4
+ %h4
+ Features
+ %hr
+ %p
+ Sign up
+ %span.light.pull-right
+ = boolean_to_icon gitlab_config.signup_enabled
+ %p
+ LDAP
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.ldap.enabled
+ %p
+ Gravatar
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.gravatar.enabled
+ %p
+ OmniAuth
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.omniauth.enabled
+ .span4
+ %h4 Components
+ %hr
+ %p
+ GitLab
+ %span.pull-right
+ = Gitlab::VERSION
+ %p
+ GitLab Shell
+ %span.pull-right
+ = Gitlab::Shell.new.version
+++ /dev/null
-<h2>Resend confirmation instructions</h2>
-
-<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
- <%= devise_error_messages! %>
-
- <div><%= f.label :email %><br />
- <%= f.email_field :email %></div>
-
- <div><%= f.submit "Resend confirmation instructions" %></div>
-<% end %>
-
-<%= render partial: "devise/shared/links" %>
--- /dev/null
+.login-box
+ %h3.page-title Resend confirmation instructions
+ = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
+ = devise_error_messages!
+ = f.email_field :email, placeholder: 'Email'
+ %div= f.submit "Resend confirmation instructions", class: 'btn btn-success'
+ %hr
+ = link_to "Sign in", new_session_path(resource_name)
%html{ lang: "en"}
= render "layouts/head", title: group_head_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "group: #{@group.name}"
= render "layouts/flash"
%nav.main-nav
%html{ lang: "en"}
= render "layouts/head", title: "Profile"
%body{class: "#{app_theme} profile", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "Profile"
= render "layouts/flash"
%nav.main-nav
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
= render "layouts/flash"
- if allowed_tree_edit?
= link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-small"
- else
- %span.btn.btn-small.disabled Edit
+ %span.btn.btn-small.disabled edit
= link_to "raw", project_raw_path(@project, @id), class: "btn btn-small", target: "_blank"
-# only show normal/blame view links for text files
- if @blob.text?
- else
= link_to "blame", project_blame_path(@project, @id), class: "btn btn-small" unless @blob.empty?
= link_to "history", project_commits_path(@project, @id), class: "btn btn-small"
+
+ - if allowed_tree_edit?
+ = link_to '#modal-remove-blob', class: "remove-blob btn btn-small btn-remove", "data-toggle" => "modal" do
+ remove
--- /dev/null
+%div#modal-remove-blob.modal.hide
+ .modal-header
+ %a.close{href: "#", "data-dismiss" => "modal"} ×
+ %h3.page-title Remove #{@blob.name}
+ %p.light
+ From branch
+ %strong= @ref
+
+ .modal-body
+ = form_tag project_blob_path(@project, @id), method: :delete do
+ .control-group.commit_message-group
+ = label_tag 'commit_message', class: "control-label" do
+ Commit message
+ .controls
+ = text_area_tag 'commit_message', params[:commit_message], placeholder: "Removed this file because...", required: true, rows: 3
+ .control-group
+ .controls
+ = submit_tag 'Remove file', class: 'btn btn-remove'
+ = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
= render 'shared/ref_switcher', destination: 'blob', path: @path
%div#tree-holder.tree-holder
= render 'blob', blob: @blob
+
+- if allowed_tree_edit?
+ = render 'projects/blob/remove'
%i.icon-code-fork
Fork Error!
%p
- You are trying to fork
+ You tried to fork
= link_to_project @project
- but it fails due to next reason:
+ but it failed for the following reason:
- if @forked_project && @forked_project.errors.any?
%ul.nav.nav-tabs
= nav_link(controller: :issues) do
- = link_to 'Browse Issues', project_issues_path(@project), class: "tab"
+ = link_to project_issues_path(@project), class: "tab" do
+ Browse Issues
+ - if current_controller?(:issues)
+ %span.badge.issue_counter #{@issues.total_count}
= nav_link(controller: :milestones) do
= link_to 'Milestones', project_milestones_path(@project), class: "tab"
= nav_link(controller: :labels) do
= link_to 'Labels', project_labels_path(@project), class: "tab"
- - if current_user
+
+ - if current_controller?(:issues)
+ - if current_user
+ %li
+ = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
+ %i.icon-rss
+
%li.pull-right
- = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
- %i.icon-rss
+ .pull-right
+ - if can? current_user, :write_issue, @project
+ = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-right", title: "New Issue", id: "new_issue_link" do
+ %i.icon-plus
+ New Issue
+ = form_tag project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right issue-search-form' do
+ = hidden_field_tag :status, params[:status], id: 'search_status'
+ = hidden_field_tag :assignee_id, params[:assignee_id], id: 'search_assignee_id'
+ = hidden_field_tag :milestone_id, params[:milestone_id], id: 'search_milestone_id'
+ = hidden_field_tag :label_name, params[:label_name], id: 'search_label_name'
+ = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'input-xpadding issue_search input-xlarge append-right-10 search-text-input' }
= form_tag bulk_update_project_issues_path(@project), method: :post do
%span Update selected issues with
= select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
- = select_tag('update[assignee_id]', options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]), prompt: "Assignee")
- = select_tag('update[milestone_id]', options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone")
+ = select_tag('update[assignee_id]', bulk_update_assignee_options, prompt: "Assignee")
+ = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
= hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag :status, params[:status]
= button_tag "Save", class: "btn update_selected_issues btn-small btn-save"
%strong= milestone.title
%small.light= milestone.expires_at
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort
+ - else
+ Newest
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(sort: 'newest') do
+ Newest
+ = link_to project_filter_path(sort: 'oldest') do
+ Oldest
+ = link_to project_filter_path(sort: 'recently_updated') do
+ Recently updated
+ = link_to project_filter_path(sort: 'last_updated') do
+ Last updated
+ = link_to project_filter_path(sort: 'milestone_due_soon') do
+ Milestone due soon
+ = link_to project_filter_path(sort: 'milestone_due_later') do
+ Milestone due later
+
%ul.well-list.issues-list
= render @issues
= render "head"
-.issues_content
- %h3.page-title
- Issues
- %span (<span class=issue_counter>#{@issues.total_count}</span>)
- .pull-right
- .span6
- - if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-right", title: "New Issue", id: "new_issue_link" do
- %i.icon-plus
- New Issue
- = form_tag project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right' do
- = hidden_field_tag :status, params[:status], id: 'search_status'
- = hidden_field_tag :assignee_id, params[:assignee_id], id: 'search_assignee_id'
- = hidden_field_tag :milestone_id, params[:milestone_id], id: 'search_milestone_id'
- = hidden_field_tag :label_name, params[:label_name], id: 'search_label_name'
- = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'input-xpadding issue_search input-xlarge append-right-10 search-text-input' }
-
.row
.span3
= render 'shared/project_filter', project_entities_path: project_issues_path(@project)
%h3.page-title
- - if @service.activated?
- %span.cgreen
- %i.icon-circle
- - else
- %span.cgray
- %i.icon-circle-blank
= @service.title
+ = boolean_to_icon @service.activated?
%p= @service.description
- @services.each do |service|
%li
%h4
- - if service.activated?
- %span.cgreen
- %i.icon-circle
- - else
- %span.cgray
- %i.icon-circle-blank
= link_to edit_project_service_path(@project, service.to_param) do
= service.title
+ .pull-right
+ = boolean_to_icon service.activated?
%p= service.description
.project-home-panel
.row
- .span4
+ .span5
%h4.project-home-title
= @project.name_with_namespace
- if @project.public
- else
%span.public-label Private
- .span8
+ .span7
.project-home-dropdown
= render "dropdown"
.form-horizontal
= link_to "Edit", edit_snippet_path(@snippet), class: "btn btn-tiny", title: 'Edit Snippet'
= link_to "Delete", snippet_path(@snippet), method: :delete, confirm: "Are you sure?", class: "btn btn-tiny", title: 'Delete Snippet'
= link_to "Raw", raw_snippet_path(@snippet), class: "btn btn-tiny", target: "_blank"
- .file-content.code
- - unless @snippet.content.empty?
- %div{class: user_color_scheme_class}
- = raw @snippet.colorize(formatter: :gitlab)
+ - unless @snippet.content.empty?
+ - if gitlab_markdown?(@snippet.file_name)
+ .file-content.wiki
+ = preserve do
+ = markdown(@snippet.data)
+ - elsif markup?(@snippet.file_name)
+ .file-content.wiki
+ = raw GitHub::Markup.render(@snippet.file_name, @snippet.data)
- else
+ .file-content.code
+ %div{class: user_color_scheme_class}
+ = raw @snippet.colorize(formatter: :gitlab)
+ - else
+ .file-content.code
%p.nothing_here_message Empty file
= f.label :title
.controls= f.text_field :title, placeholder: "Example Snippet", class: 'input-xlarge', required: true
.control-group
- = f.label "Private?"
+ = f.label "Access"
.controls
- = f.check_box :private, {class: ''}
+ = f.label :private_true, class: 'radio-label' do
+ = f.radio_button :private, true
+ %span
+ %strong Private
+ (only you can see this snippet)
+ %br
+ = f.label :private_false, class: 'radio-label' do
+ = f.radio_button :private, false
+ %span
+ %strong Public
+ (GitLab users can can see this snippet)
+
.control-group
.file-editor
= f.label :file_name, "File"
- else
= f.submit 'Save', class: "btn-save btn"
- = link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
- unless @snippet.new_record?
- .pull-right= link_to 'Destroy', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
+ .pull-right.prepend-left-20
+ = link_to 'Remove', snippet_path(@snippet), confirm: 'Removed snippet cannot be restored! Are you sure?', method: :delete, class: "btn btn-remove delete-snippet", id: "destroy_snippet_#{@snippet.id}"
+ = link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
:javascript
= link_to reliable_snippet_path(snippet) do
= truncate(snippet.title, length: 60)
- if snippet.private?
- %span.label.label-success
+ %span.label.label-gray
%i.icon-lock
private
%span.cgray.monospace.tiny.pull-right
## Automatic issue closing
# If a commit message matches this regular expression, all issues referenced from the matched text will be closed.
- # This happends when the commit is pushed or merged into the default branch of a project.
+ # This happens when the commit is pushed or merged into the default branch of a project.
# When not specified the default issue_closing_pattern as specified below will be used.
# issue_closing_pattern: ([Cc]lose[sd]|[Ff]ixe[sd]) +#\d+
# ==> Configuration for :validatable
# Range for password length. Default is 6..128.
- config.password_length = 6..128
+ config.password_length = 8..128
# Email regex used to validate email formats. It simply asserts that
# an one (and only one) @ exists in the given string. This is mainly
paths_to_be_protected = [
"#{Rails.application.config.relative_url_root}/users/password",
"#{Rails.application.config.relative_url_root}/users/sign_in",
+ "#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session.json",
+ "#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session",
"#{Rails.application.config.relative_url_root}/users"
]
-Rack::Attack.throttle('protected paths', limit: 6, period: 60.seconds) do |req|
- req.ip if paths_to_be_protected.include?(req.path) && req.post?
+
+unless Rails.env.test?
+ Rack::Attack.throttle('protected paths', limit: 10, period: 60.seconds) do |req|
+ req.ip if paths_to_be_protected.include?(req.path) && req.post?
+ end
end
end
scope module: :projects do
- resources :blob, only: [:show], constraints: {id: /.+/}
+ resources :blob, only: [:show, :destroy], constraints: {id: /.+/}
resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit'
### List projects
-Get a list of projects owned by the authenticated user.
+Get a list of projects accessible by the authenticated user.
```
GET /projects
```
+#### List owned projects
+
+Get a list of projects owned by the authenticated user.
+
+```
+GET /projects/owned
+```
+
+#### List ALL projects
+
+Get a list of all GitLab projects (admin only).
+
+```
+GET /projects/all
+```
+
### Get single project
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME , which is owned by the authentication user.
Parameters:
-+ `file_name` (required) - The name of new file. Ex. class.rb
-+ `file_path` (optional) - The path to new file. Ex. lib/
++ `file_path` (optional) - Full path to new file. Ex. lib/class.rb
+ `branch_name` (required) - The name of branch
+ `content` (required) - File content
+ `commit_message` (required) - Commit message
+ `branch_name` (required) - The name of branch
+ `content` (required) - New file content
+ `commit_message` (required) - Commit message
+
+## Delete existing file in repository
+
+```
+DELETE /projects/:id/repository/files
+```
+
+Parameters:
+
++ `file_path` (required) - Full path to file. Ex. lib/class.rb
++ `branch_name` (required) - The name of branch
++ `commit_message` (required) - Commit message
--- /dev/null
+# GitLab project architecture
+
+GitLab project consists of two parts: GitLab and GitLab shell.
+
+## GitLab
+
+Web application with background jobs workers.
+Provides you with UI and most of functionality.
+For some operations like repo creation - uses GitLab shell.
+
+Uses:
+ * Ruby as main language for application code and most libraries.
+ * [Rails](http://rubyonrails.org/) web framework as main framework for application.
+ * Mysql or postgres as main databases. Used for persistent data storage(users, project, issues etc).
+ * Redis database. Used for cache and exchange data between some components.
+ * Python2 because of [pygments](http://pygments.org/) as code syntax highlighter.
+
+## GitLab shell
+
+Command line ruby application. Used by GitLab through shell commands.
+It provides interface to all kind of manipulations with repositories and ssh keys.
+Full list of commands you can find in README of GitLab shell repo.
+Works on pure ruby and do not require any additional software.
Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
- curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p247.tar.gz | tar xz
- cd ruby-2.0.0-p247
+ curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p353.tar.gz | tar xz
+ cd ruby-2.0.0-p353
./configure --disable-install-rdoc
make
sudo make install
cd gitlab-shell
# switch to right version
- sudo -u git -H git checkout v1.7.8
+ sudo -u git -H git checkout v1.7.9
sudo -u git -H cp config.yml.example config.yml
cd /home/git/gitlab
# Checkout to stable release
- sudo -u git -H git checkout 6-2-stable
+ sudo -u git -H git checkout 6-3-stable
**Note:**
-You can change `6-2-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+You can change `6-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
## Configure it
# Operating Systems
-## Linux
-
GitLab is developed for the Linux operating system.
-GitLab officially supports (recent versions of) these Linux distributions:
+## GitLab officially supports
- Ubuntu Linux
- Debian/GNU Linux
-It should also work on (though they are not officially supported):
+## GitLab.com offers paid support for
-- Arch
+- Red Hat Enterprise Linux (RHEL)
- CentOS
+- Oracle Linux
+
+## Not officially supported
+
+- Arch Linux
- Fedora
- Gentoo
-- RHEL
-## Other Unix Systems
+On the above distributions it is pretty easy to install GitLab yourself.
+
+## Unsupported Unix Systems
-There is nothing that prevents GitLab from running on other Unix operating
-systems. This means you may get it to work on systems running FreeBSD or OS X.
-**If you want to try, please proceed with caution!**
+There is nothing that prevents GitLab from running on other Unix operating systems.
+This means you may get it to work on systems running FreeBSD or OS X.
+If you want to do this, please be aware it could be a lot of work.
+Please consider using a virtual machine to run GitLab.
-## Windows
+## Other operating systems such as Windows
-GitLab does **not** run on Windows and we have no plans of supporting it in the
-near future. Please consider using a virtual machine to run GitLab.
+GitLab does **not** run on Windows and we have no plans of supporting it in the near future.
+Please consider using a virtual machine to run GitLab.
-# Rubies
+# Ruby versions
-GitLab requires Ruby (MRI) 1.9.3 and several Gems with native components.
-While it is generally possible to use other Rubies (like
-[JRuby](http://jruby.org/) or [Rubinius](http://rubini.us/)) it might require
-some work on your part.
+GitLab requires Ruby (MRI) 1.9.3 or 2.0+.
+While it is generally possible to use other Rubies
+(like [JRuby](http://jruby.org/) or [Rubinius](http://rubini.us/))
+it might require some work since GitLab uses several Gems that have native extensions.
# Hardware requirements
1. Verify that the issue can be repoduced
1. Acknowledge the issue to the researcher that disclosed it
-1. Fix the issue on a feature branch, do this on the private dev.gitlab.org server and update the VERSION and CHANGELOG
+1. Fix the issue on a feature branch, do this on the private GitLab development server and update the VERSION and CHANGELOG in this branch
1. Consider creating and testing workarounds
1. Create feature branches for the blog posts on GitLab.org and GitLab.com and link them from the code branch
-1. Merge the code feature branch
-1. Create a git tag vX.X.X for CE and another one for EE
+1. Merge the code feature branch into master
+1. Cherry-pick the code into the latest stable branch
+1. Create a git tag vX.X.X for CE and another patch release for EE
1. Push the code and the tags to all the CE and EE repositories
+1. Apply the patch to GitLab Cloud and the private GitLab development server
1. Merge and publish the blog posts
1. Send tweets about the release from @gitlabhq and @git_lab
1. Send out an email to the subscribers mailing list on MailChimp
1. Send out an email to [the community google mailing list](https://groups.google.com/forum/#!forum/gitlabhq)
1. Send out an email to [the GitLab newsletter list](http://gitlab.us5.list-manage.com/subscribe?u=498dccd07cf3e9482bee33ba4&id=98a9a4992c)
-1. Post a signed copy of our announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number
+1. Post a signed copy of our complete announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number
1. Add the security researcher to the [Security Researcher Acknowledgments list](http://www.gitlab.com/vulnerability-acknowledgements/)
1. Thank the security researcher in an email for their cooperation
-1. Update the blogposts when we receive a CVE number
+1. Update the blogpost and the CHANGELOG when we receive the CVE number
+
+The timing of the code merge into master should be coordinated in advance.
+After the merge we strive to publish the announcements within 60 minutes.
## Blog post template
XXX Security Advisory for GitLab
A recently discovered critical vulnerability in GitLab allows [unauthenticated API access|remote code execution|unauthorized access to repositories|XXX|PICKSOMETHING]. All users should update GitLab and gitlab-shell immediately.
+We [have|haven't|XXX|PICKSOMETHING|] heard of this vulnerability being actively exploited.
### Version affected
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.7.9 # Addresses multiple critical security vulnerabilities
```
### 4. Install libs, migrations, etc.
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8
+sudo -u git -H git checkout v1.7.9
```
### 4. Install additional packages
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.7.9 # Addresses multiple critical security vulnerabilities
```
### 4. Install libs, migrations, etc.
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8
+sudo -u git -H git checkout v1.7.9
```
### 4. Install additional packages
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8
+sudo -u git -H git checkout v1.7.9
```
### 4. Install libs, migrations, etc.
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.7.9 # Addresses multiple critical security vulnerabilities
```
### 5. Install libs, migrations, etc.
TIP: to see what changed in gitlab.yml.example in this release use next command:
```
-git diff 6-1-stable:config/gitlab.yml.example 6-2-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 6-2-stable:config/gitlab.yml.example
```
* Make `/home/git/gitlab/config/gitlab.yml` same as https://github.com/gitlabhq/gitlabhq/blob/6-2-stable/config/gitlab.yml.example but with your settings.
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.7.9 # Addresses multiple critical security vulnerabilities
```
### 4. Install additional packages
--- /dev/null
+# From 6.2 to 6.3
+
+## Requires version: 6.1 or 6.2
+
+### 0. Backup
+
+It's useful to make a backup just in case things go south:
+(With MySQL, this may require granting "LOCK TABLES" privileges to the GitLab user on the database version)
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 1. Stop server
+
+ sudo service gitlab stop
+
+### 2. Get latest code
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H git fetch
+sudo -u git -H git checkout 6-3-stable
+```
+
+### 3. Update gitlab-shell (and its config)
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v1.7.9 # Addresses multiple critical security vulnerabilities
+```
+
+The Gitlab-shell config changed recently, so check for config file changes and make `/home/git/gitlab-shell/config.yml` the same as https://github.com/gitlabhq/gitlab-shell/blob/master/config.yml.example
+
+### 4. Install additional packages
+
+```bash
+# Add support for lograte for better log file handling
+sudo apt-get install logrotate
+```
+
+### 5. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL
+sudo -u git -H bundle install --without development test postgres --deployment
+
+#PostgreSQL
+sudo -u git -H bundle install --without development test mysql --deployment
+
+
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+sudo -u git -H bundle exec rake assets:clean RAILS_ENV=production
+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
+sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+```
+
+### 6. Update config files
+
+TIP: to see what changed in gitlab.yml.example in this release use next command:
+
+```
+git diff 6-2-stable:config/gitlab.yml.example 6-3-stable:config/gitlab.yml.example
+git diff 6-1-stable:config/gitlab.yml.example 6-3-stable:config/gitlab.yml.example # if you upgrading from 6-1
+```
+
+* Make `/home/git/gitlab/config/gitlab.yml` same as https://github.com/gitlabhq/gitlabhq/blob/6-3-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` same as https://github.com/gitlabhq/gitlabhq/blob/6-3-stable/config/unicorn.rb.example but with your settings.
+* Copy rack attack middleware config
+
+```bash
+sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb
+```
+* Set up logrotate
+
+```bash
+sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
+```
+
+### 7. Update Init script
+
+```bash
+sudo rm /etc/init.d/gitlab
+sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/6-3-stable/lib/support/init.d/gitlab
+sudo chmod +x /etc/init.d/gitlab
+```
+
+### 8. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 9. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade complete!
+
+## Things went south? Revert to previous version (6.2)
+
+### 1. Revert the code to the previous version
+Follow the [`upgrade guide from 6.1 to 6.2`](6.1-to-6.2.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.7.8
+sudo -u git -H git checkout v1.7.9
```
### 4. Install libs, migrations, etc.
--- /dev/null
+# Updating Ruby from source
+
+This guide explains how to update Ruby in case you installed it from source according to the instructions in https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md#2-ruby .
+
+### 1. Look for Ruby versions
+This guide will only update `/usr/local/bin/ruby`. You can see which Ruby binaries are installed on your system by running:
+
+```bash
+ls -l $(which -a ruby)
+```
+
+### 2. Stop GitLab
+
+```bash
+sudo service gitlab stop
+```
+
+### 3. Install or update dependencies
+Here we are assuming you are using Debian/Ubuntu.
+
+```bash
+sudo apt-get install build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl
+```
+
+### 4. Download, compile and install Ruby
+Find the latest stable version of Ruby 1.9 or 2.0 at https://www.ruby-lang.org/en/downloads/ . We recommend at least 2.0.0p353, which is patched against [CVE-2013-4164](https://www.ruby-lang.org/en/news/2013/11/22/heap-overflow-in-floating-point-parsing-cve-2013-4164/).
+
+```bash
+cd /tmp
+curl --progress http://cache.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p353.tar.gz | tar xz
+cd ruby-2.0.0-p353
+./configure --disable-install-rdoc
+make
+sudo make install # overwrite the existing Ruby in /usr/local/bin
+```
+
+### 5. Reinstall GitLab gem bundle
+Just to be sure we will reinstall the gems used by GitLab. Note that the `bundle install` command [depends on your choice of database](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md#install-gems).
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H rm -rf vendor/bundle # remove existing Gem bundle
+sudo -u git -H bundle install --deployment --without development test postgres aws # Assuming MySQL
+```
+
+### 6. Start GitLab
+We are now ready to restart GitLab.
+
+```bash
+sudo service gitlab start
+```
+
+### Done
And I click Flowdock service link
And I fill Flowdock settings
Then I should see Flowdock service settings saved
+
+ Scenario: Activate Assembla service
+ When I visit project "Shop" services page
+ And I click Assembla service link
+ And I fill Assembla settings
+ Then I should see Assembla service settings saved
\ No newline at end of file
step 'I try change my password w/o old one' do
within '.update-password' do
- fill_in "user_password", with: "222333"
- fill_in "user_password_confirmation", with: "222333"
+ fill_in "user_password", with: "22233344"
+ fill_in "user_password_confirmation", with: "22233344"
click_button "Save"
end
end
step 'I change my password' do
within '.update-password' do
- fill_in "user_current_password", with: "123456"
- fill_in "user_password", with: "222333"
- fill_in "user_password_confirmation", with: "222333"
+ fill_in "user_current_password", with: "12345678"
+ fill_in "user_password", with: "22233344"
+ fill_in "user_password_confirmation", with: "22233344"
click_button "Save"
end
end
step 'I unsuccessfully change my password' do
within '.update-password' do
- fill_in "user_current_password", with: "123456"
+ fill_in "user_current_password", with: "12345678"
fill_in "user_password", with: "password"
fill_in "user_password_confirmation", with: "confirmation"
click_button "Save"
page.should have_content 'Campfire'
page.should have_content 'Hipchat'
page.should have_content 'GitLab CI'
+ page.should have_content 'Assembla'
end
And 'I click gitlab-ci service link' do
Then 'I should see Flowdock service settings saved' do
find_field('Token').value.should == 'verySecret'
end
+
+ And 'I click Assembla service link' do
+ click_link 'Assembla'
+ end
+
+ And 'I fill Assembla settings' do
+ check 'Active'
+ fill_in 'Token', with: 'verySecret'
+ click_button 'Save'
+ end
+
+ Then 'I should see Assembla service settings saved' do
+ find_field('Token').value.should == 'verySecret'
+ end
end
end
And 'I click link "Destroy"' do
- click_link "Destroy"
+ click_link "Remove"
end
And 'I submit new snippet "Personal snippet three"' do
end
And 'I uncheck "Private" checkbox' do
- find(:xpath, "//input[@id='personal_snippet_private']").set true
+ choose "Public"
click_button "Save"
end
# Create new file in repository
#
# Parameters:
- # file_name (required) - The name of new file. Ex. class.rb
- # file_path (optional) - The path to new file. Ex. lib/
+ # file_path (optional) - The path to new file. Ex. lib/class.rb
# branch_name (required) - The name of branch
# content (required) - File content
# commit_message (required) - Commit message
# POST /projects/:id/repository/files
#
post ":id/repository/files" do
- required_attributes! [:file_name, :branch_name, :content, :commit_message]
- attrs = attributes_for_keys [:file_name, :file_path, :branch_name, :content, :commit_message]
+ required_attributes! [:file_path, :branch_name, :content, :commit_message]
+ attrs = attributes_for_keys [:file_path, :branch_name, :content, :commit_message]
branch_name = attrs.delete(:branch_name)
file_path = attrs.delete(:file_path)
result = ::Files::CreateContext.new(user_project, current_user, attrs, branch_name, file_path).execute
status(201)
{
- file_name: attrs[:file_name],
file_path: file_path,
branch_name: branch_name
}
# Update existing file in repository
#
# Parameters:
- # file_name (required) - The name of new file. Ex. class.rb
- # file_path (optional) - The path to new file. Ex. lib/
+ # file_path (optional) - The path to file. Ex. lib/class.rb
# branch_name (required) - The name of branch
# content (required) - File content
# commit_message (required) - Commit message
render_api_error!(result[:error], 400)
end
end
+
+ # Delete existing file in repository
+ #
+ # Parameters:
+ # file_path (optional) - The path to file. Ex. lib/class.rb
+ # branch_name (required) - The name of branch
+ # content (required) - File content
+ # commit_message (required) - Commit message
+ #
+ # Example Request:
+ # DELETE /projects/:id/repository/files
+ #
+ delete ":id/repository/files" do
+ required_attributes! [:file_path, :branch_name, :commit_message]
+ attrs = attributes_for_keys [:file_path, :branch_name, :commit_message]
+ branch_name = attrs.delete(:branch_name)
+ file_path = attrs.delete(:file_path)
+ result = ::Files::DeleteContext.new(user_project, current_user, attrs, branch_name, file_path).execute
+
+ if result[:status] == :success
+ status(200)
+
+ {
+ file_path: file_path,
+ branch_name: branch_name
+ }
+ else
+ render_api_error!(result[:error], 400)
+ end
+ end
end
end
end
-
present @projects, with: Entities::Project
end
+ # Get all projects for admin user
+ #
+ # Example Request:
+ # GET /projects/all
+ get '/all' do
+ authenticated_as_admin!
+ @projects = paginate Project
+ present @projects, with: Entities::Project
+ end
+
# Get a single project
#
# Parameters:
def dump
case config["adapter"]
when /^mysql/ then
- system("mysqldump #{mysql_args} #{config['database']} > #{db_file_name}")
+ system('mysqldump', *mysql_args, config['database'], out: db_file_name)
when "postgresql" then
pg_env
- system("pg_dump #{config['database']} > #{db_file_name}")
+ system('pg_dump', config['database'], out: db_file_name)
end
end
def restore
case config["adapter"]
when /^mysql/ then
- system("mysql #{mysql_args} #{config['database']} < #{db_file_name}")
+ system('mysql', *mysql_args, config['database'], in: db_file_name)
when "postgresql" then
pg_env
- system("psql #{config['database']} -f #{db_file_name}")
+ system('psql', config['database'], '-f', db_file_name)
end
end
'encoding' => '--default-character-set',
'password' => '--password'
}
- args.map { |opt, arg| "#{arg}='#{config[opt]}'" if config[opt] }.compact.join(' ')
+ args.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
end
def pg_env
module Backup
class Manager
+ BACKUP_CONTENTS = %w{repositories/ db/ uploads/ backup_information.yml}
+
def pack
# saving additional informations
s = {}
# create archive
print "Creating backup archive: #{s[:backup_created_at].to_i}_gitlab_backup.tar ... "
- if Kernel.system("tar -cf #{s[:backup_created_at].to_i}_gitlab_backup.tar repositories/ db/ uploads/ backup_information.yml")
+ if Kernel.system('tar', '-cf', "#{s[:backup_created_at].to_i}_gitlab_backup.tar", *BACKUP_CONTENTS)
puts "done".green
else
puts "failed".red
def cleanup
print "Deleting tmp directories ... "
- if Kernel.system("rm -rf repositories/ db/ uploads/ backup_information.yml")
+ if Kernel.system('rm', '-rf', *BACKUP_CONTENTS)
puts "done".green
else
puts "failed".red
file_list.map! { |f| $1.to_i if f =~ /(\d+)_gitlab_backup.tar/ }
file_list.sort.each do |timestamp|
if Time.at(timestamp) < (Time.now - keep_time)
- if system("rm #{timestamp}_gitlab_backup.tar")
+ if Kernel.system(*%W(rm #{timestamp}_gitlab_backup.tar))
removed += 1
end
end
end
print "Unpacking backup ... "
- unless Kernel.system("tar -xf #{tar_file}")
+ unless Kernel.system(*%W(tar -xf #{tar_file}))
puts "failed".red
exit 1
else
# Create namespace dir if missing
FileUtils.mkdir_p(File.join(backup_repos_path, project.namespace.path)) if project.namespace
- if system("cd #{path_to_repo(project)} > /dev/null 2>&1 && git bundle create #{path_to_bundle(project)} --all > /dev/null 2>&1")
+ if system(*%W(git --git-dir=#{path_to_repo(project)} bundle create #{path_to_bundle(project)} --all), silent)
puts "[DONE]".green
else
puts "[FAILED]".red
print " * #{wiki.path_with_namespace} ... "
if wiki.empty?
puts " [SKIPPED]".cyan
- elsif system("cd #{path_to_repo(wiki)} > /dev/null 2>&1 && git bundle create #{path_to_bundle(wiki)} --all > /dev/null 2>&1")
+ elsif system(*%W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all), silent)
puts " [DONE]".green
else
puts " [FAILED]".red
project.namespace.ensure_dir_exist if project.namespace
- if system("git clone --bare #{path_to_bundle(project)} #{path_to_repo(project)} > /dev/null 2>&1")
+ if system(*%W(git clone --bare #{path_to_bundle(project)} #{path_to_repo(project)}), silent)
puts "[DONE]".green
else
puts "[FAILED]".red
if File.exists?(path_to_bundle(wiki))
print " * #{wiki.path_with_namespace} ... "
- if system("git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)} > /dev/null 2>&1")
+ if system(*%W(git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)}), silent)
puts " [DONE]".green
else
puts " [FAILED]".red
print 'Put GitLab hooks in repositories dirs'.yellow
gitlab_shell_user_home = File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}")
- if system("#{gitlab_shell_user_home}/gitlab-shell/support/rewrite-hooks.sh #{Gitlab.config.gitlab_shell.repos_path}")
+ if system("#{gitlab_shell_user_home}/gitlab-shell/support/rewrite-hooks.sh", Gitlab.config.gitlab_shell.repos_path)
puts " [DONE]".green
else
puts " [FAILED]".red
FileUtils.rm_rf(backup_repos_path)
FileUtils.mkdir_p(backup_repos_path)
end
+
+ def silent
+ {err: '/dev/null', out: '/dev/null'}
+ end
end
end
FileUtils.cp_r(backup_uploads_dir, app_uploads_dir)
end
-
+
def backup_existing_uploads_dir
if File.exists?(app_uploads_dir)
FileUtils.mv(app_uploads_dir, Rails.root.join('public', "uploads.#{Time.now.to_i}"))
when 'git-upload-pack'
project.public || can?(user, :download_code, project)
when'git-receive-pack'
- action = if project.protected_branch?(ref)
- :push_code_to_protected_branches
- else
- :push_code
- end
+ refs.each do |ref|
+ action = if project.protected_branch?(ref)
+ :push_code_to_protected_branches
+ else
+ :push_code
+ end
+
+ return false unless can?(user, action, project)
+ end
- can?(user, action, project)
+ true
else
false
end
@project ||= project_by_path(@request.path_info)
end
- def ref
- @ref ||= parse_ref
+ def refs
+ @refs ||= parse_refs
end
- def parse_ref
+ def parse_refs
input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
Zlib::GzipReader.new(@request.body).read
else
# Need to reset seek point
@request.body.rewind
- /refs\/heads\/([\/\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
+
+ # Parse refs
+ refs = input.force_encoding('ascii-8bit').scan(/refs\/heads\/([\/\w\.-]+)/n).flatten.compact
+
+ # Cleanup grabare from refs
+ # if push to multiple branches
+ refs.map do |ref|
+ ref.gsub(/00.*/, "")
+ end
end
end
end
Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
end
+ # Return GitLab shell version
+ def version
+ gitlab_shell_version_file = "#{gitlab_shell_user_home}/gitlab-shell/VERSION"
+
+ if File.readable?(gitlab_shell_version_file)
+ File.read(gitlab_shell_version_file)
+ end
+ end
+
protected
def gitlab_shell_user_home
--- /dev/null
+require_relative 'file_action'
+
+module Gitlab
+ module Satellite
+ class DeleteFileAction < FileAction
+ # Deletes file and creates a new commit for it
+ #
+ # Returns false if committing the change fails
+ # Returns false if pushing from the satellite to bare repo failed or was rejected
+ # Returns true otherwise
+ def commit!(content, commit_message)
+ in_locked_and_timed_satellite do |repo|
+ prepare_satellite!(repo)
+
+ # create target branch in satellite at the corresponding commit from bare repo
+ repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
+
+ # update the file in the satellite's working dir
+ file_path_in_satellite = File.join(repo.working_dir, file_path)
+
+ # Prevent relative links
+ unless safe_path?(file_path_in_satellite)
+ Gitlab::GitLogger.error("FileAction: Relative path not allowed")
+ return false
+ end
+
+ File.delete(file_path_in_satellite)
+
+ # add removed file
+ repo.remove(file_path_in_satellite)
+
+ # commit the changes
+ # will raise CommandFailed when commit fails
+ repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
+
+
+ # push commit back to bare repo
+ # will raise CommandFailed when push fails
+ repo.git.push({raise: true, timeout: true}, :origin, ref)
+
+ # everything worked
+ true
+ end
+ rescue Grit::Git::CommandFailed => ex
+ Gitlab::GitLogger.error(ex.message)
+ false
+ end
+ end
+ end
+end
#
# Returns false if the ref has been updated while editing the file
# Returns false if committing the change fails
- # Returns false if pushing from the satellite to Gitolite failed or was rejected
+ # Returns false if pushing from the satellite to bare repo failed or was rejected
# Returns true otherwise
def commit!(content, commit_message)
in_locked_and_timed_satellite do |repo|
prepare_satellite!(repo)
- # create target branch in satellite at the corresponding commit from Gitolite
+ # create target branch in satellite at the corresponding commit from bare repo
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
# update the file in the satellite's working dir
file_path_in_satellite = File.join(repo.working_dir, file_path)
+
+ # Prevent relative links
+ unless safe_path?(file_path_in_satellite)
+ Gitlab::GitLogger.error("FileAction: Relative path not allowed")
+ return false
+ end
+
File.open(file_path_in_satellite, 'w') { |f| f.write(content) }
# commit the changes
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
- # push commit back to Gitolite
+ # push commit back to bare repo
# will raise CommandFailed when push fails
repo.git.push({raise: true, timeout: true}, :origin, ref)
@file_path = file_path
@ref = ref
end
+
+ def safe_path?(path)
+ File.absolute_path(path) == path
+ end
end
end
end
#
# Returns false if the ref has been updated while editing the file
# Returns false if committing the change fails
- # Returns false if pushing from the satellite to Gitolite failed or was rejected
+ # Returns false if pushing from the satellite to bare repo failed or was rejected
# Returns true otherwise
def commit!(content, commit_message)
in_locked_and_timed_satellite do |repo|
prepare_satellite!(repo)
- # create target branch in satellite at the corresponding commit from Gitolite
+ # create target branch in satellite at the corresponding commit from bare repo
repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
- # update the file in the satellite's working dir
file_path_in_satellite = File.join(repo.working_dir, file_path)
+ dir_name_in_satellite = File.dirname(file_path_in_satellite)
+
+ # Prevent relative links
+ unless safe_path?(file_path_in_satellite)
+ Gitlab::GitLogger.error("FileAction: Relative path not allowed")
+ return false
+ end
+
+ # Create dir if not exists
+ FileUtils.mkdir_p(dir_name_in_satellite)
+
+ # Write file
File.open(file_path_in_satellite, 'w') { |f| f.write(content) }
# add new file
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
- # push commit back to Gitolite
+ # push commit back to bare repo
# will raise CommandFailed when push fails
repo.git.push({raise: true, timeout: true}, :origin, ref)
in_locked_and_timed_satellite do |merge_repo|
prepare_satellite!(merge_repo)
if merge_in_satellite!(merge_repo)
- # push merge back to Gitolite
+ # push merge back to bare repo
# will raise CommandFailed when push fails
merge_repo.git.push(default_options, :origin, merge_request.target_branch)
# remove source branch
remotes.each { |name| repo.git.remote(default_options,'rm', name)}
end
- # Updates the satellite from Gitolite
+ # Updates the satellite from bare repo
#
# Note: this will only update remote branches (i.e. origin/*)
def update_from_source!
end
def gitlab_shell_version
- gitlab_shell_version_file = "#{gitlab_shell_user_home}/gitlab-shell/VERSION"
- if File.readable?(gitlab_shell_version_file)
- File.read(gitlab_shell_version_file)
- end
+ Gitlab::Shell.new.version
end
def has_gitlab_shell3?
end
def check_gitlab_shell
- required_version = Gitlab::VersionInfo.new(1, 7, 8)
+ required_version = Gitlab::VersionInfo.new(1, 7, 9)
current_version = Gitlab::VersionInfo.parse(gitlab_shell_version)
print "GitLab Shell version >= #{required_version} ? ... "
--- /dev/null
+require 'spec_helper'
+
+describe Issues::ListContext do
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, creator: user) }
+
+ titles = ['foo','bar','baz']
+ titles.each_with_index do |title, index|
+ let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) }
+ end
+
+ describe 'sorting' do
+
+ it 'sorts by newest' do
+ params = {:sort => 'newest'}
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq foo
+ end
+
+ it 'sorts by oldest' do
+ params = {:sort => 'oldest'}
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq baz
+ end
+
+ it 'sorts by recently updated' do
+ params = {:sort => 'recently_updated'}
+ baz.updated_at = Time.now + 10
+ baz.save
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq baz
+ end
+
+ it 'sorts by least recently updated' do
+ params = {:sort => 'last_updated'}
+ bar.updated_at = Time.now - 10
+ bar.save
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq bar
+ end
+
+ describe 'sorting by milestone' do
+
+ let(:newer_due_milestone) { create(:milestone, :due_date => '2013-12-11') }
+ let(:later_due_milestone) { create(:milestone, :due_date => '2013-12-12') }
+
+ before :each do
+ foo.milestone = newer_due_milestone
+ foo.save
+ bar.milestone = later_due_milestone
+ bar.save
+ end
+
+ it 'sorts by most recently due milestone' do
+ params = {:sort => 'milestone_due_soon'}
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq foo
+
+ end
+
+ it 'sorts by least recently due milestone' do
+ params = {:sort => 'milestone_due_later'}
+
+ issues = Issues::ListContext.new(project, user, params).execute
+ issues.first.should eq bar
+ end
+
+ end
+ end
+
+end
email { Faker::Internet.email }
name
sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" }
- password "123456"
+ password "12345678"
password_confirmation { password }
confirmed_at { Time.now }
confirmation_token { nil }
page.should have_content 'gitlab'
end
end
+
+ describe 'filter issue' do
+ titles = ['foo','bar','baz']
+ titles.each_with_index do |title, index|
+ let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) }
+ end
+ let(:newer_due_milestone) { create(:milestone, :due_date => '2013-12-11') }
+ let(:later_due_milestone) { create(:milestone, :due_date => '2013-12-12') }
+
+ it 'sorts by newest' do
+ visit project_issues_path(project, sort: 'newest')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'foo')
+ page.should have_selector("ul.issues-list li:last-child", :text => 'baz')
+ end
+
+ it 'sorts by oldest' do
+ visit project_issues_path(project, sort: 'oldest')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'baz')
+ page.should have_selector("ul.issues-list li:last-child", :text => 'foo')
+ end
+
+ it 'sorts by most recently updated' do
+ baz.updated_at = Time.now + 100
+ baz.save
+ visit project_issues_path(project, sort: 'recently_updated')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'baz')
+ end
+
+ it 'sorts by least recently updated' do
+ baz.updated_at = Time.now - 100
+ baz.save
+ visit project_issues_path(project, sort: 'last_updated')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'baz')
+ end
+
+ describe 'sorting by milestone' do
+
+ before :each do
+ foo.milestone = newer_due_milestone
+ foo.save
+ bar.milestone = later_due_milestone
+ bar.save
+ end
+
+ it 'sorts by recently due milestone' do
+ visit project_issues_path(project, sort: 'milestone_due_soon')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'foo')
+ end
+
+ it 'sorts by least recently due milestone' do
+ visit project_issues_path(project, sort: 'milestone_due_later')
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'bar')
+ end
+ end
+
+ describe 'combine filter and sort' do
+
+ let(:user2) { create(:user) }
+
+ before :each do
+ foo.assignee = user2
+ foo.save
+ bar.assignee = user2
+ bar.save
+ end
+
+ it 'sorts with a filter applied' do
+ visit project_issues_path(project, sort: 'oldest', assignee_id: user2.id)
+
+ page.should have_selector("ul.issues-list li:first-child", :text => 'bar')
+ page.should have_selector("ul.issues-list li:last-child", :text => 'foo')
+ page.should_not have_content 'baz'
+
+ end
+ end
+ end
+
end
it "should leave code blocks untouched" do
helper.stub(:user_color_scheme_class).and_return(:white)
- helper.markdown("\n some code from $#{snippet.id}\n here too\n").should include("<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>")
+ target_html = "<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> <span class=\"err\">$</span><span class=\"mi\">#{snippet.id}</span>"
- helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should include("<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>")
+ helper.markdown("\n some code from $#{snippet.id}\n here too\n").should include(target_html)
+ helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should include(target_html)
end
it "should leave inline code untouched" do
@user = create(
:user,
username: 'john',
- password: '888777',
- password_confirmation: '888777'
+ password: '88877711',
+ password_confirmation: '88877711'
)
end
it "should find user by valid login/password" do
- gl_auth.find('john', '888777').should == @user
+ gl_auth.find('john', '88877711').should == @user
end
it "should not find user with invalid password" do
- gl_auth.find('john', 'invalid').should_not == @user
+ gl_auth.find('john', 'invalid11').should_not == @user
end
it "should not find user with invalid login and password" do
- gl_auth.find('jon', 'invalid').should_not == @user
+ gl_auth.find('jon', 'invalid11').should_not == @user
end
end
end
--- /dev/null
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# token :string(255)
+# project_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean default(FALSE), not null
+# project_url :string(255)
+# subdomain :string(255)
+# room :string(255)
+#
+
+require 'spec_helper'
+
+describe AssemblaService do
+ describe "Associations" do
+ it { should belong_to :project }
+ it { should have_one :service_hook }
+ end
+
+ describe "Execute" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project_with_code) }
+
+ before do
+ @assembla_service = AssemblaService.new
+ @assembla_service.stub(
+ project_id: project.id,
+ project: project,
+ service_hook: true,
+ token: 'verySecret'
+ )
+ @sample_data = GitPushService.new.sample_data(project, user)
+ @api_url = 'https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=verySecret'
+ WebMock.stub_request(:post, @api_url)
+ end
+
+ it "should call FlowDock API" do
+ @assembla_service.execute(@sample_data)
+ WebMock.should have_requested(:post, @api_url).with(
+ body: /#{@sample_data[:before]}.*#{@sample_data[:after]}.*#{project.path}/
+ ).once
+ end
+ end
+end
end
it "should not generate password by default" do
- user = create(:user, password: 'abcdefg')
- user.password.should == 'abcdefg'
+ user = create(:user, password: 'abcdefghe')
+ user.password.should == 'abcdefghe'
end
it "should generate password when forcing random password" do
describe "POST /projects/:id/repository/files" do
let(:valid_params) {
{
- file_name: 'newfile.rb',
+ file_path: 'newfile.rb',
branch_name: 'master',
content: 'puts 8',
commit_message: 'Added newfile'
post api("/projects/#{project.id}/repository/files", user), valid_params
response.status.should == 201
- json_response['file_name'].should == 'newfile.rb'
+ json_response['file_path'].should == 'newfile.rb'
end
it "should return a 400 bad request if no params given" do
response.status.should == 400
end
end
+
+ describe "DELETE /projects/:id/repository/files" do
+ let(:valid_params) {
+ {
+ file_path: 'spec/spec_helper.rb',
+ branch_name: 'master',
+ commit_message: 'Changed file'
+ }
+ }
+
+ it "should delete existing file in project repo" do
+ Gitlab::Satellite::DeleteFileAction.any_instance.stub(
+ commit!: true,
+ )
+
+ delete api("/projects/#{project.id}/repository/files", user), valid_params
+ response.status.should == 200
+ json_response['file_path'].should == 'spec/spec_helper.rb'
+ end
+
+ it "should return a 400 bad request if no params given" do
+ delete api("/projects/#{project.id}/repository/files", user)
+ response.status.should == 400
+ end
+
+ it "should return a 400 if satellite fails to create file" do
+ Gitlab::Satellite::DeleteFileAction.any_instance.stub(
+ commit!: false,
+ )
+
+ delete api("/projects/#{project.id}/repository/files", user), valid_params
+ response.status.should == 400
+ end
+ end
end
end
end
+ describe "GET /projects/all" do
+ context "when unauthenticated" do
+ it "should return authentication error" do
+ get api("/projects/all")
+ response.status.should == 401
+ end
+ end
+
+ context "when authenticated as regular user" do
+ it "should return authentication error" do
+ get api("/projects/all", user)
+ response.status.should == 403
+ end
+ end
+
+ context "when authenticated as admin" do
+ it "should return an array of all projects" do
+ get api("/projects/all", admin)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['name'].should == project.name
+ json_response.first['owner']['email'].should == user.email
+ end
+ end
+ end
+
describe "POST /projects" do
context "maximum number of projects reached" do
before do
describe "POST /session" do
context "when valid password" do
it "should return private token" do
- post api("/session"), email: user.email, password: '123456'
+ post api("/session"), email: user.email, password: '12345678'
response.status.should == 201
json_response['email'].should == user.email
def login_with(user)
visit new_user_session_path
fill_in "user_login", with: user.email
- fill_in "user_password", with: "123456"
+ fill_in "user_password", with: "12345678"
click_button "Sign in"
Thread.current[:current_user] = user
end
remove_repository: true,
update_repository_head: true,
add_key: true,
- remove_key: true
+ remove_key: true,
+ version: '6.3.0'
)
Gitlab::Satellite::Satellite.any_instance.stub(