diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | doc/api/builds.md | 39 | ||||
-rw-r--r-- | lib/api/builds.rb | 26 | ||||
-rw-r--r-- | lib/api/entities.rb | 5 | ||||
-rw-r--r-- | spec/requests/api/builds_spec.rb | 25 |
5 files changed, 96 insertions, 0 deletions
diff --git a/CHANGELOG b/CHANGELOG index d7e7795dcb1..9a7ec480bc2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -57,6 +57,7 @@ v 8.5.0 (unreleased) - Don't process cross-reference notes from forks - Fix: init.d script not working on OS X - Faster snippet search + - Added API to download build artifacts - Title for milestones should be unique (Zeger-Jan van de Weg) - Validate correctness of maximum attachment size application setting - Replaces "Create merge request" link with one to the "Merge Request" when one exists diff --git a/doc/api/builds.md b/doc/api/builds.md index 6977dedfa9e..295e037df5f 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -34,6 +34,10 @@ Example of response "coverage": null, "created_at": "2015-12-24T15:51:21.802Z", "download_url": null, + "artifacts_file": { + "filename": "artifacts.zip", + "size": 1000 + }, "finished_at": "2015-12-24T17:54:27.895Z", "id": 7, "name": "teaspoon", @@ -72,6 +76,7 @@ Example of response "coverage": null, "created_at": "2015-12-24T15:51:21.727Z", "download_url": null, + "artifacts_file": null, "finished_at": "2015-12-24T17:54:24.921Z", "id": 6, "name": "spinach:other", @@ -135,6 +140,7 @@ Example of response "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", "download_url": null, + "artifacts_file": null, "finished_at": "2016-01-11T10:14:09.526Z", "id": 69, "name": "rubocop", @@ -159,6 +165,7 @@ Example of response "coverage": null, "created_at": "2015-12-24T15:51:21.957Z", "download_url": null, + "artifacts_file": null, "finished_at": "2015-12-24T17:54:33.913Z", "id": 9, "name": "brakeman", @@ -220,6 +227,7 @@ Example of response "coverage": null, "created_at": "2015-12-24T15:51:21.880Z", "download_url": null, + "artifacts_file": null, "finished_at": "2015-12-24T17:54:31.198Z", "id": 8, "name": "rubocop", @@ -247,6 +255,35 @@ Example of response } ``` +## Get a build artifacts + +Get a build artifacts of a project + +``` +GET /projects/:id/builds/:build_id/artifacts +``` + +### Parameters + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| id | integer | yes | The ID of a project | +| build\_id | integer | yes | The ID of a build | + +### Example of request + +``` +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds/8" +``` + +### Response: + + +| Status | Description | +|-----------|---------------------------------| +| 200 | Serves the artifacts file | +| 404 | Build not found or no artifacts | + ## Cancel a build Cancel a single build of a project @@ -280,6 +317,7 @@ Example of response "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", "download_url": null, + "artifacts_file": null, "finished_at": "2016-01-11T10:14:09.526Z", "id": 69, "name": "rubocop", @@ -326,6 +364,7 @@ Example of response "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", "download_url": null, + "artifacts_file": null, "finished_at": null, "id": 69, "name": "rubocop", diff --git a/lib/api/builds.rb b/lib/api/builds.rb index c058128ae54..f5ae8e57e23 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -60,6 +60,32 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end + # Download the artifacts file from build + # + # Parameters: + # id (required) - The ID of a build + # token (required) - The build authorization token + # Example Request: + # GET /projects/:id/builds/:build_id/artifacts + get ':id/builds/:build_id/artifacts' do + authorize_read_builds! + + build = get_build(params[:build_id]) + return not_found!(build) unless build + + artifacts_file = build.artifacts_file + + unless artifacts_file.file_storage? + return redirect_to build.artifacts_file.url + end + + unless artifacts_file.exists? + not_found! + end + + present_file!(artifacts_file.path, artifacts_file.filename) + end + # Get a trace of a specific build of a project # # Parameters: diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 857705dbf12..eaf42bee113 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -391,6 +391,10 @@ module API end end + class BuildArtifactFile < Grape::Entity + expose :filename, :size + end + class Build < Grape::Entity expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at @@ -402,6 +406,7 @@ module API repo_obj.artifacts_download_url end end + expose :artifacts_file, using: BuildArtifactFile, if: lambda { |build, opts| build.artifacts? } expose :commit, with: RepoCommit do |repo_obj, _options| if repo_obj.respond_to?(:commit) repo_obj.commit.commit_data diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index adbae5dcad8..e915294cc9d 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -11,6 +11,7 @@ describe API::API, api: true do let(:commit) { create(:ci_commit, project: project)} let(:build) { create(:ci_build, commit: commit) } let(:build_with_trace) { create(:ci_build_with_trace, commit: commit) } + let(:build_with_artifacts) { create(:ci_build, :artifacts, commit: commit) } let(:build_canceled) { create(:ci_build, :canceled, commit: commit) } describe 'GET /projects/:id/builds ' do @@ -92,6 +93,30 @@ describe API::API, api: true do end end + describe 'GET /projects/:id/builds/:build_id/artifacts' do + context 'authorized user' do + it 'should return specific build trace' do + get api("/projects/#{project.id}/builds/#{build_with_artifacts.id}/artifacts", user) + + expect(response.status).to eq(200) + end + + it 'should not return build artifacts if not uploaded' do + get api("/projects/#{project.id}/builds/#{build.id}/artifacts", user) + + expect(response.status).to eq(404) + end + end + + context 'unauthorized user' do + it 'should not return specific build artifacts' do + get api("/projects/#{project.id}/builds/#{build_with_artifacts.id}/trace") + + expect(response.status).to eq(401) + end + end + end + describe 'GET /projects/:id/builds/:build_id/trace' do context 'authorized user' do it 'should return specific build trace' do |