gitlab-org--gitlab-foss/lib/api/commits.rb
Lin Jen-Shin 4587c78afa Merge remote-tracking branch 'upstream/master' into fix-git-hooks-when-creating-file
* upstream/master: (1122 commits)
  Update CHANGELOG.md for 8.16.2
  Display project ID in project settings (!8572)
  fixed points from comments to improve code quality
  Update CHANGELOG.md for 8.14.8
  Statisfy eslint
  Add CHANGELOG entry
  Fix access to the wiki code via HTTP when repository feature disabled
  Display fullscreen button on small screens (!5302)
  Prevent removing fields from dropdowns on input elements
  fix for all themes
  Return struct instead of multiple values
  Fix race conditions for AuthorizedProjectsWorker
  Add User#nested_groups and User#nested_projects methods
  Fix spec failure due to timestamp ordering issue in mySQL
  Fixed error with filter keyboard tests
  `can?` already includes the `feature_available?` check
  Test there is no Merge Request button when MRs are disabled
  Ensure the correct Merge Request button is found
  Add 409 conflict tests
  Add CHANGELOG
  ...
2017-01-26 17:21:38 +08:00

203 lines
7.4 KiB
Ruby

require 'mime/types'
module API
class Commits < Grape::API
include PaginationParams
before { authenticate! }
before { authorize! :download_code, user_project }
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
desc 'Get a project repository commits' do
success Entities::RepoCommit
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
optional :since, type: String, desc: 'Only commits after or in this date will be returned'
optional :until, type: String, desc: 'Only commits before or in this date will be returned'
optional :page, type: Integer, default: 0, desc: 'The page for pagination'
optional :per_page, type: Integer, default: 20, desc: 'The number of results per page'
optional :path, type: String, desc: 'The file path'
end
get ":id/repository/commits" do
# TODO remove the next line for 9.0, use DateTime type in the params block
datetime_attributes! :since, :until
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
offset = params[:page] * params[:per_page]
commits = user_project.repository.commits(ref,
path: params[:path],
limit: params[:per_page],
offset: offset,
after: params[:since],
before: params[:until])
present commits, with: Entities::RepoCommit
end
desc 'Commit multiple file changes as one commit' do
success Entities::RepoCommitDetail
detail 'This feature was introduced in GitLab 8.13'
end
params do
requires :branch_name, type: String, desc: 'The name of branch'
requires :commit_message, type: String, desc: 'Commit message'
requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
optional :author_email, type: String, desc: 'Author email for commit'
optional :author_name, type: String, desc: 'Author name for commit'
end
post ":id/repository/commits" do
authorize! :push_code, user_project
attrs = declared_params
attrs[:start_branch] = attrs[:branch_name]
attrs[:target_branch] = attrs[:branch_name]
attrs[:actions].map! do |action|
action[:action] = action[:action].to_sym
action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/')
action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/')
action
end
result = ::Files::MultiService.new(user_project, current_user, attrs).execute
if result[:status] == :success
commit_detail = user_project.repository.commits(result[:result], limit: 1).first
present commit_detail, with: Entities::RepoCommitDetail
else
render_api_error!(result[:message], 400)
end
end
desc 'Get a specific commit of a project' do
success Entities::RepoCommitDetail
failure [[404, 'Not Found']]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end
get ":id/repository/commits/:sha" do
commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit
present commit, with: Entities::RepoCommitDetail
end
desc 'Get the diff for a specific commit of a project' do
failure [[404, 'Not Found']]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end
get ":id/repository/commits/:sha/diff" do
commit = user_project.commit(params[:sha])
not_found! "Commit" unless commit
commit.raw_diffs.to_a
end
desc "Get a commit's comments" do
success Entities::CommitNote
failure [[404, 'Not Found']]
end
params do
use :pagination
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
end
get ':id/repository/commits/:sha/comments' do
commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit
notes = Note.where(commit_id: commit.id).order(:created_at)
present paginate(notes), with: Entities::CommitNote
end
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
success Entities::RepoCommit
end
params do
requires :sha, type: String, desc: 'A commit sha to be cherry picked'
requires :branch, type: String, desc: 'The name of the branch'
end
post ':id/repository/commits/:sha/cherry_pick' do
authorize! :push_code, user_project
commit = user_project.commit(params[:sha])
not_found!('Commit') unless commit
branch = user_project.repository.find_branch(params[:branch])
not_found!('Branch') unless branch
commit_params = {
commit: commit,
create_merge_request: false,
target_branch: params[:branch]
}
result = ::Commits::CherryPickService.new(user_project, current_user, commit_params).execute
if result[:status] == :success
branch = user_project.repository.find_branch(params[:branch])
present user_project.repository.commit(branch.dereferenced_target), with: Entities::RepoCommit
else
render_api_error!(result[:message], 400)
end
end
desc 'Post comment to commit' do
success Entities::CommitNote
end
params do
requires :sha, type: String, regexp: /\A\h{6,40}\z/, desc: "The commit's SHA"
requires :note, type: String, desc: 'The text of the comment'
optional :path, type: String, desc: 'The file path'
given :path do
requires :line, type: Integer, desc: 'The line number'
requires :line_type, type: String, values: ['new', 'old'], default: 'new', desc: 'The type of the line'
end
end
post ':id/repository/commits/:sha/comments' do
commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit
opts = {
note: params[:note],
noteable_type: 'Commit',
commit_id: commit.id
}
if params[:path]
commit.raw_diffs(all_diffs: true).each do |diff|
next unless diff.new_path == params[:path]
lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
lines.each do |line|
next unless line.new_pos == params[:line] && line.type == params[:line_type]
break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
end
break if opts[:line_code]
end
opts[:type] = LegacyDiffNote.name if opts[:line_code]
end
note = ::Notes::CreateService.new(user_project, current_user, opts).execute
if note.save
present note, with: Entities::CommitNote
else
render_api_error!("Failed to save note #{note.errors.messages}", 400)
end
end
end
end
end