commits_spec.rb 15 KB
Newer Older
1 2 3
require 'spec_helper'
require 'mime/types'

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
4
describe API::API, api: true  do
5 6 7
  include ApiHelpers
  let(:user) { create(:user) }
  let(:user2) { create(:user) }
Marc Siegfriedt's avatar
Marc Siegfriedt committed
8
  let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
9 10
  let!(:master) { create(:project_member, :master, user: user, project: project) }
  let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
11
  let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
12
  let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') }
13 14 15

  before { project.team << [user, :reporter] }

Marc Siegfriedt's avatar
Marc Siegfriedt committed
16
  describe "List repository commits" do
17 18 19
    context "authorized user" do
      before { project.team << [user2, :reporter] }

20
      it "returns project commits" do
21
        get api("/projects/#{project.id}/repository/commits", user)
22
        expect(response).to have_http_status(200)
23

24 25
        expect(json_response).to be_an Array
        expect(json_response.first['id']).to eq(project.repository.commit.id)
26 27 28 29
      end
    end

    context "unauthorized user" do
30
      it "does not return project commits" do
31
        get api("/projects/#{project.id}/repository/commits")
32
        expect(response).to have_http_status(401)
33 34
      end
    end
35 36

    context "since optional parameter" do
37
      it "returns project commits since provided parameter" do
38 39 40 41 42 43 44 45 46 47 48 49
        commits = project.repository.commits("master")
        since = commits.second.created_at

        get api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user)

        expect(json_response.size).to eq 2
        expect(json_response.first["id"]).to eq(commits.first.id)
        expect(json_response.second["id"]).to eq(commits.second.id)
      end
    end

    context "until optional parameter" do
50
      it "returns project commits until provided parameter" do
51 52 53 54 55
        commits = project.repository.commits("master")
        before = commits.second.created_at

        get api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user)

56 57 58 59 60 61
        if commits.size >= 20
          expect(json_response.size).to eq(20)
        else
          expect(json_response.size).to eq(commits.size - 1)
        end

62 63 64 65 66 67
        expect(json_response.first["id"]).to eq(commits.second.id)
        expect(json_response.second["id"]).to eq(commits.third.id)
      end
    end

    context "invalid xmlschema date parameters" do
68
      it "returns an invalid parameter error message" do
69 70
        get api("/projects/#{project.id}/repository/commits?since=invalid-date", user)

71
        expect(response).to have_http_status(400)
72 73 74
        expect(json_response['message']).to include "\"since\" must be a timestamp in ISO 8601 format"
      end
    end
75 76
  end

Marc Siegfriedt's avatar
Marc Siegfriedt committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  describe "Create a commit with multiple files and actions" do
    let!(:url) { "/projects/#{project.id}/repository/commits" }

    it 'returns a 403 unauthorized for user without permissions' do
      post api(url, user2)

      expect(response).to have_http_status(403)
    end

    it 'returns a 400 bad request if no params are given' do
      post api(url, user)

      expect(response).to have_http_status(400)
    end

    context :create do
      let(:message) { 'Created file' }
      let!(:invalid_c_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'create',
              file_path: 'files/ruby/popen.rb',
              content: 'puts 8'
            }
          ]
        }
      end
      let!(:valid_c_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'create',
              file_path: 'foo/bar/baz.txt',
              content: 'puts 8'
            }
          ]
        }
      end

      it 'a new file in project repo' do
        post api(url, user), valid_c_params

        expect(response).to have_http_status(201)
        expect(json_response['title']).to eq(message)
      end

      it 'returns a 400 bad request if file exists' do
        post api(url, user), invalid_c_params

        expect(response).to have_http_status(400)
      end
    end

    context :delete do
      let(:message) { 'Deleted file' }
      let!(:invalid_d_params) do
        {
          branch_name: 'markdown',
          commit_message: message,
          actions: [
            {
              action: 'delete',
              file_path: 'doc/api/projects.md'
            }
          ]
        }
      end
      let!(:valid_d_params) do
        {
          branch_name: 'markdown',
          commit_message: message,
          actions: [
            {
              action: 'delete',
              file_path: 'doc/api/users.md'
            }
          ]
        }
      end

      it 'an existing file in project repo' do
        post api(url, user), valid_d_params

        expect(response).to have_http_status(201)
        expect(json_response['title']).to eq(message)
      end

      it 'returns a 400 bad request if file does not exist' do
        post api(url, user), invalid_d_params

        expect(response).to have_http_status(400)
      end
    end

    context :move do
      let(:message) { 'Moved file' }
      let!(:invalid_m_params) do
        {
          branch_name: 'feature',
          commit_message: message,
          actions: [
            {
              action: 'move',
              file_path: 'CHANGELOG',
              previous_path: 'VERSION',
              content: '6.7.0.pre'
            }
          ]
        }
      end
      let!(:valid_m_params) do
        {
          branch_name: 'feature',
          commit_message: message,
          actions: [
            {
              action: 'move',
              file_path: 'VERSION.txt',
              previous_path: 'VERSION',
              content: '6.7.0.pre'
            }
          ]
        }
      end

      it 'an existing file in project repo' do
        post api(url, user), valid_m_params

        expect(response).to have_http_status(201)
        expect(json_response['title']).to eq(message)
      end

      it 'returns a 400 bad request if file does not exist' do
        post api(url, user), invalid_m_params

        expect(response).to have_http_status(400)
      end
    end

    context :update do
      let(:message) { 'Updated file' }
      let!(:invalid_u_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'update',
              file_path: 'foo/bar.baz',
              content: 'puts 8'
            }
          ]
        }
      end
      let!(:valid_u_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'update',
              file_path: 'files/ruby/popen.rb',
              content: 'puts 8'
            }
          ]
        }
      end

      it 'an existing file in project repo' do
        post api(url, user), valid_u_params

        expect(response).to have_http_status(201)
        expect(json_response['title']).to eq(message)
      end

      it 'returns a 400 bad request if file does not exist' do
        post api(url, user), invalid_u_params

        expect(response).to have_http_status(400)
      end
    end

    context "multiple operations" do
      let(:message) { 'Multiple actions' }
      let!(:invalid_mo_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'create',
              file_path: 'files/ruby/popen.rb',
              content: 'puts 8'
            },
            {
              action: 'delete',
              file_path: 'doc/api/projects.md'
            },
            {
              action: 'move',
              file_path: 'CHANGELOG',
              previous_path: 'VERSION',
              content: '6.7.0.pre'
            },
            {
              action: 'update',
              file_path: 'foo/bar.baz',
              content: 'puts 8'
            }
          ]
        }
      end
      let!(:valid_mo_params) do
        {
          branch_name: 'master',
          commit_message: message,
          actions: [
            {
              action: 'create',
              file_path: 'foo/bar/baz.txt',
              content: 'puts 8'
            },
            {
              action: 'delete',
              file_path: 'Gemfile.zip'
            },
            {
              action: 'move',
              file_path: 'VERSION.txt',
              previous_path: 'VERSION',
              content: '6.7.0.pre'
            },
            {
              action: 'update',
              file_path: 'files/ruby/popen.rb',
              content: 'puts 8'
            }
          ]
        }
      end

      it 'are commited as one in project repo' do
        post api(url, user), valid_mo_params

        expect(response).to have_http_status(201)
        expect(json_response['title']).to eq(message)
      end

      it 'return a 400 bad request if there are any issues' do
        post api(url, user), invalid_mo_params

        expect(response).to have_http_status(400)
      end
    end
  end

  describe "Get a single commit" do
339
    context "authorized user" do
340
      it "returns a commit by sha" do
341
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
342

343
        expect(response).to have_http_status(200)
344 345
        expect(json_response['id']).to eq(project.repository.commit.id)
        expect(json_response['title']).to eq(project.repository.commit.title)
346 347 348
        expect(json_response['stats']['additions']).to eq(project.repository.commit.stats.additions)
        expect(json_response['stats']['deletions']).to eq(project.repository.commit.stats.deletions)
        expect(json_response['stats']['total']).to eq(project.repository.commit.stats.total)
349 350
      end

351
      it "returns a 404 error if not found" do
352
        get api("/projects/#{project.id}/repository/commits/invalid_sha", user)
353
        expect(response).to have_http_status(404)
354
      end
355

356
      it "returns nil for commit without CI" do
357
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
358

359
        expect(response).to have_http_status(200)
Kamil Trzcinski's avatar
Kamil Trzcinski committed
360
        expect(json_response['status']).to be_nil
361 362
      end

363
      it "returns status for CI" do
364
        pipeline = project.ensure_pipeline('master', project.repository.commit.sha)
365 366
        pipeline.update(status: 'success')

367
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
368

369
        expect(response).to have_http_status(200)
370
        expect(json_response['status']).to eq(pipeline.status)
371
      end
372 373

      it "returns status for CI when pipeline is created" do
374
        project.ensure_pipeline('master', project.repository.commit.sha)
375 376 377 378

        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)

        expect(response).to have_http_status(200)
379
        expect(json_response['status']).to eq("created")
380
      end
381 382 383
    end

    context "unauthorized user" do
384
      it "does not return the selected commit" do
385
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}")
386
        expect(response).to have_http_status(401)
387 388 389 390
      end
    end
  end

Marc Siegfriedt's avatar
Marc Siegfriedt committed
391
  describe "Get the diff of a commit" do
392 393 394
    context "authorized user" do
      before { project.team << [user2, :reporter] }

395
      it "returns the diff of the selected commit" do
396
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
397
        expect(response).to have_http_status(200)
398

399 400 401
        expect(json_response).to be_an Array
        expect(json_response.length).to be >= 1
        expect(json_response.first.keys).to include "diff"
402 403
      end

404
      it "returns a 404 error if invalid commit" do
405
        get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user)
406
        expect(response).to have_http_status(404)
407 408 409 410
      end
    end

    context "unauthorized user" do
411
      it "does not return the diff of the selected commit" do
412
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff")
413
        expect(response).to have_http_status(401)
414 415 416
      end
    end
  end
417

Marc Siegfriedt's avatar
Marc Siegfriedt committed
418
  describe 'Get the comments of a commit' do
419
    context 'authorized user' do
420
      it 'returns merge_request comments' do
421
        get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
422
        expect(response).to have_http_status(200)
423
        expect(json_response).to be_an Array
424
        expect(json_response.length).to eq(2)
425 426
        expect(json_response.first['note']).to eq('a comment on a commit')
        expect(json_response.first['author']['id']).to eq(user.id)
427 428
      end

429
      it 'returns a 404 error if merge_request_id not found' do
430
        get api("/projects/#{project.id}/repository/commits/1234ab/comments", user)
431
        expect(response).to have_http_status(404)
432 433 434 435
      end
    end

    context 'unauthorized user' do
436
      it 'does not return the diff of the selected commit' do
437
        get api("/projects/#{project.id}/repository/commits/1234ab/comments")
438
        expect(response).to have_http_status(401)
439 440 441 442
      end
    end
  end

Marc Siegfriedt's avatar
Marc Siegfriedt committed
443
  describe 'Post comment to commit' do
444
    context 'authorized user' do
445
      it 'returns comment' do
446
        post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment'
447
        expect(response).to have_http_status(201)
448 449 450 451
        expect(json_response['note']).to eq('My comment')
        expect(json_response['path']).to be_nil
        expect(json_response['line']).to be_nil
        expect(json_response['line_type']).to be_nil
452 453
      end

454
      it 'returns the inline comment' do
455 456
        post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment', path: project.repository.commit.raw_diffs.first.new_path, line: 1, line_type: 'new'

457
        expect(response).to have_http_status(201)
458
        expect(json_response['note']).to eq('My comment')
459
        expect(json_response['path']).to eq(project.repository.commit.raw_diffs.first.new_path)
460
        expect(json_response['line']).to eq(1)
461
        expect(json_response['line_type']).to eq('new')
462 463
      end

464
      it 'returns 400 if note is missing' do
465
        post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
466
        expect(response).to have_http_status(400)
467 468
      end

469
      it 'returns 404 if note is attached to non existent commit' do
470
        post api("/projects/#{project.id}/repository/commits/1234ab/comments", user), note: 'My comment'
471
        expect(response).to have_http_status(404)
472 473 474 475
      end
    end

    context 'unauthorized user' do
476
      it 'does not return the diff of the selected commit' do
477
        post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments")
478
        expect(response).to have_http_status(401)
479 480 481
      end
    end
  end
482
end