BigW Consortium Gitlab

commits.rb 6.44 KB
Newer Older
1 2 3
require 'mime/types'

module API
4
  # Projects commits API
5 6 7 8
  class Commits < Grape::API
    before { authenticate! }
    before { authorize! :download_code, user_project }

9 10 11
    params do
      requires :id, type: String, desc: 'The ID of a project'
    end
12
    resource :projects do
13 14 15 16 17 18 19 20 21
      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'
22
        optional :path,     type: String, desc: 'The file path'
23
      end
24
      get ":id/repository/commits" do
25
        # TODO remove the next line for 9.0, use DateTime type in the params block
26 27
        datetime_attributes! :since, :until

28
        ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
29 30 31
        offset = params[:page] * params[:per_page]

        commits = user_project.repository.commits(ref,
32
                                                  path: params[:path],
33 34 35 36
                                                  limit: params[:per_page],
                                                  offset: offset,
                                                  after: params[:since],
                                                  before: params[:until])
37 38 39 40

        present commits, with: Entities::RepoCommit
      end

Marc Siegfriedt committed
41
      desc 'Commit multiple file changes as one commit' do
42
        success Entities::RepoCommitDetail
Marc Siegfriedt committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
        detail 'This feature was introduced in GitLab 8.13'
      end
      params do
        requires :id, type: Integer, desc: 'The project ID'
        requires :branch_name, type: String, desc: 'The name of branch'
        requires :commit_message, type: String, desc: 'Commit message'
        requires :actions, type: Array, 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[:source_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

76 77 78 79 80 81 82
      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
83
      get ":id/repository/commits/:sha" do
84 85
        commit = user_project.commit(params[:sha])

86
        not_found! "Commit" unless commit
87

88 89 90
        present commit, with: Entities::RepoCommitDetail
      end

91 92 93 94 95 96
      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
97
      get ":id/repository/commits/:sha/diff" do
98 99
        commit = user_project.commit(params[:sha])

100
        not_found! "Commit" unless commit
101

102
        commit.raw_diffs.to_a
103
      end
104

105 106 107 108 109 110 111 112 113
      desc "Get a commit's comments" do
        success Entities::CommitNote
        failure [[404, 'Not Found']]
      end
      params do
        requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
        optional :per_page, type: Integer, desc: 'The amount of items per page for paginaion'
        optional :page, type: Integer, desc: 'The page number for pagination'
      end
114
      get ':id/repository/commits/:sha/comments' do
115 116
        commit = user_project.commit(params[:sha])

117
        not_found! 'Commit' unless commit
118
        notes = Note.where(commit_id: commit.id).order(:created_at)
119

120 121 122
        present paginate(notes), with: Entities::CommitNote
      end

123 124 125 126 127 128 129 130 131 132 133 134
      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
135
      post ':id/repository/commits/:sha/comments' do
136
        commit = user_project.commit(params[:sha])
137
        not_found! 'Commit' unless commit
138

139 140 141 142 143 144
        opts = {
          note: params[:note],
          noteable_type: 'Commit',
          commit_id: commit.id
        }

145
        if params[:path]
146
          commit.raw_diffs(all_diffs: true).each do |diff|
147
            next unless diff.new_path == params[:path]
148
            lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
149 150

            lines.each do |line|
151
              next unless line.new_pos == params[:line] && line.type == params[:line_type]
152 153 154 155 156
              break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
            end

            break if opts[:line_code]
          end
157 158

          opts[:type] = LegacyDiffNote.name if opts[:line_code]
159 160 161 162 163 164 165
        end

        note = ::Notes::CreateService.new(user_project, current_user, opts).execute

        if note.save
          present note, with: Entities::CommitNote
        else
166
          render_api_error!("Failed to save note #{note.errors.messages}", 400)
167 168
        end
      end
169 170 171
    end
  end
end