BigW Consortium Gitlab

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

module API
  class Commits < Grape::API
5 6
    include PaginationParams

7 8 9
    before { authenticate! }
    before { authorize! :download_code, user_project }

10 11 12
    params do
      requires :id, type: String, desc: 'The ID of a project'
    end
13
    resource :projects do
14 15 16 17 18
      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'
19 20
        optional :since,    type: DateTime, desc: 'Only commits after or on this date will be returned'
        optional :until,    type: DateTime, desc: 'Only commits before or on this date will be returned'
21 22
        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'
23
        optional :path,     type: String, desc: 'The file path'
24
      end
25 26
      get ":id/repository/commits" do
        ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
27 28 29
        offset = params[:page] * params[:per_page]

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

        present commits, with: Entities::RepoCommit
      end

Marc Siegfriedt committed
39
      desc 'Commit multiple file changes as one commit' do
40
        success Entities::RepoCommitDetail
Marc Siegfriedt committed
41 42 43
        detail 'This feature was introduced in GitLab 8.13'
      end
      params do
44
        requires :branch, type: String, desc: 'The name of branch'
Marc Siegfriedt committed
45
        requires :commit_message, type: String, desc: 'Commit message'
46
        requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
Marc Siegfriedt committed
47 48 49 50 51 52
        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

53 54
        attrs = declared_params.merge(start_branch: declared_params[:branch], target_branch: declared_params[:branch])

Marc Siegfriedt committed
55 56 57 58 59 60 61 62 63 64
        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

65 66 67 68 69 70 71
      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
72
      get ":id/repository/commits/:sha" do
73 74
        commit = user_project.commit(params[:sha])

75
        not_found! "Commit" unless commit
76

77 78 79
        present commit, with: Entities::RepoCommitDetail
      end

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

89
        not_found! "Commit" unless commit
90

91
        commit.raw_diffs.to_a
92
      end
93

94 95 96 97 98
      desc "Get a commit's comments" do
        success Entities::CommitNote
        failure [[404, 'Not Found']]
      end
      params do
99
        use :pagination
100 101
        requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
      end
102
      get ':id/repository/commits/:sha/comments' do
103 104
        commit = user_project.commit(params[:sha])

105
        not_found! 'Commit' unless commit
106
        notes = user_project.notes.where(commit_id: commit.id).order(:created_at)
107

108 109 110
        present paginate(notes), with: Entities::CommitNote
      end

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
      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

144 145 146 147 148 149 150 151 152
      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'
Douwe Maan committed
153
          requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line'
154 155
        end
      end
156
      post ':id/repository/commits/:sha/comments' do
157
        commit = user_project.commit(params[:sha])
158
        not_found! 'Commit' unless commit
159

160 161 162 163 164 165
        opts = {
          note: params[:note],
          noteable_type: 'Commit',
          commit_id: commit.id
        }

166
        if params[:path]
167
          commit.raw_diffs(all_diffs: true).each do |diff|
168
            next unless diff.new_path == params[:path]
169
            lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
170 171

            lines.each do |line|
172
              next unless line.new_pos == params[:line] && line.type == params[:line_type]
173 174 175 176 177
              break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
            end

            break if opts[:line_code]
          end
178 179

          opts[:type] = LegacyDiffNote.name if opts[:line_code]
180 181 182 183 184 185 186
        end

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

        if note.save
          present note, with: Entities::CommitNote
        else
187
          render_api_error!("Failed to save note #{note.errors.messages}", 400)
188 189
        end
      end
190 191 192
    end
  end
end