Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAhmet Demir <ahmet2mir+gitlab@gmail.com>2018-06-28 09:10:51 +0300
committerAchilleas Pipinellis <axil@gitlab.com>2018-06-28 09:10:51 +0300
commit80f4e7575e99c4dfe1cf7a6ccf1b055e7654be4b (patch)
treec28f6e7a6f174980e77a61ece8f60a74634f0020
parenta17d0527bed2117e2998312ad749477712827681 (diff)
Add SHA256 and HEAD on File API
-rw-r--r--changelogs/unreleased/19439-api-file-sha56-and-head.yml5
-rw-r--r--doc/api/repository_files.md34
-rw-r--r--lib/api/files.rb56
-rw-r--r--lib/api/helpers/headers_helpers.rb11
-rw-r--r--spec/requests/api/files_spec.rb85
5 files changed, 180 insertions, 11 deletions
diff --git a/changelogs/unreleased/19439-api-file-sha56-and-head.yml b/changelogs/unreleased/19439-api-file-sha56-and-head.yml
new file mode 100644
index 00000000000..4bc1e560631
--- /dev/null
+++ b/changelogs/unreleased/19439-api-file-sha56-and-head.yml
@@ -0,0 +1,5 @@
+---
+title: Add SHA256 and HEAD on File API
+merge_request: 19439
+author: ahmet2mir
+type: added
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index c29dc22e12d..49fb9bc141d 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -27,6 +27,7 @@ Example response:
"size": 1476,
"encoding": "base64",
"content": "IyA9PSBTY2hlbWEgSW5mb3...",
+ "content_sha256": "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
"ref": "master",
"blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
"commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
@@ -39,6 +40,36 @@ Parameters:
- `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `ref` (required) - The name of branch, tag or commit
+NOTE: **Note:**
+`blob_id` is the blob sha, see [repositories - Get a blob from repository](repositories.md#get-a-blob-from-repository)
+
+In addition to the `GET` method, you can also use `HEAD` to get just file metadata.
+
+```
+HEAD /projects/:id/repository/files/:file_path
+```
+
+```bash
+curl --head --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master'
+```
+
+Example response:
+
+```text
+HTTP/1.1 200 OK
+...
+X-Gitlab-Blob-Id: 79f7bbd25901e8334750839545a9bd021f0e4c83
+X-Gitlab-Commit-Id: d5a3ff139356ce33e37e73add446f16869741b50
+X-Gitlab-Content-Sha256: 4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481
+X-Gitlab-Encoding: base64
+X-Gitlab-File-Name: key.rb
+X-Gitlab-File-Path: app/models/key.rb
+X-Gitlab-Last-Commit-Id: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
+X-Gitlab-Ref: master
+X-Gitlab-Size: 1476
+...
+```
+
## Get raw file from repository
```
@@ -54,6 +85,9 @@ Parameters:
- `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb
- `ref` (required) - The name of branch, tag or commit
+NOTE: **Note:**
+Like [Get file from repository](repository_files.md#get-file-from-repository) you can use `HEAD` to get just file metadata.
+
## Create new file in repository
```
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 1598d3c00b8..29d7489bd7c 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -5,6 +5,8 @@ module API
# Prevents returning plain/text responses for files with .txt extension
after_validation { content_type "application/json" }
+ helpers ::API::Helpers::HeadersHelpers
+
helpers do
def commit_params(attrs)
{
@@ -40,6 +42,20 @@ module API
}
end
+ def blob_data
+ {
+ file_name: @blob.name,
+ file_path: @blob.path,
+ size: @blob.size,
+ encoding: "base64",
+ content_sha256: Digest::SHA256.hexdigest(@blob.data),
+ ref: params[:ref],
+ blob_id: @blob.id,
+ commit_id: @commit.id,
+ last_commit_id: @repo.last_commit_id_for_path(@commit.sha, params[:file_path])
+ }
+ end
+
params :simple_file_params do
requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.'
@@ -61,6 +77,17 @@ module API
requires :id, type: String, desc: 'The project ID'
end
resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do
+ desc 'Get raw file metadata from repository'
+ params do
+ requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
+ requires :ref, type: String, desc: 'The name of branch, tag or commit'
+ end
+ head ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS do
+ assign_file_vars!
+
+ set_http_headers(blob_data)
+ end
+
desc 'Get raw file contents from the repository'
params do
requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
@@ -69,9 +96,22 @@ module API
get ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
+ set_http_headers(blob_data)
+
send_git_blob @repo, @blob
end
+ desc 'Get file metadata from repository'
+ params do
+ requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
+ requires :ref, type: String, desc: 'The name of branch, tag or commit'
+ end
+ head ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do
+ assign_file_vars!
+
+ set_http_headers(blob_data)
+ end
+
desc 'Get a file from the repository'
params do
requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
@@ -80,17 +120,11 @@ module API
get ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
- {
- file_name: @blob.name,
- file_path: @blob.path,
- size: @blob.size,
- encoding: "base64",
- content: Base64.strict_encode64(@blob.data),
- ref: params[:ref],
- blob_id: @blob.id,
- commit_id: @commit.id,
- last_commit_id: @repo.last_commit_id_for_path(@commit.sha, params[:file_path])
- }
+ data = blob_data
+
+ set_http_headers(data)
+
+ data.merge(content: Base64.strict_encode64(@blob.data))
end
desc 'Create new file in repository'
diff --git a/lib/api/helpers/headers_helpers.rb b/lib/api/helpers/headers_helpers.rb
new file mode 100644
index 00000000000..cde51fccc62
--- /dev/null
+++ b/lib/api/helpers/headers_helpers.rb
@@ -0,0 +1,11 @@
+module API
+ module Helpers
+ module HeadersHelpers
+ def set_http_headers(header_data)
+ header_data.each do |key, value|
+ header "X-Gitlab-#{key.to_s.split('_').collect(&:capitalize).join('-')}", value
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index d8fdfd6dee1..4bc5d3ee899 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -21,6 +21,89 @@ describe API::Files do
"/projects/#{project.id}/repository/files/#{file_path}"
end
+ describe "HEAD /projects/:id/repository/files/:file_path" do
+ shared_examples_for 'repository files' do
+ it 'returns file attributes in headers' do
+ head api(route(file_path), current_user), params
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.headers['X-Gitlab-File-Path']).to eq(CGI.unescape(file_path))
+ expect(response.headers['X-Gitlab-File-Name']).to eq('popen.rb')
+ expect(response.headers['X-Gitlab-Last-Commit-Id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
+ expect(response.headers['X-Gitlab-Content-Sha256']).to eq('c440cd09bae50c4632cc58638ad33c6aa375b6109d811e76a9cc3a613c1e8887')
+ end
+
+ it 'returns file by commit sha' do
+ # This file is deleted on HEAD
+ file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee"
+ params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"
+
+ head api(route(file_path), current_user), params
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.headers['X-Gitlab-File-Name']).to eq('commit.js.coffee')
+ expect(response.headers['X-Gitlab-Content-Sha256']).to eq('08785f04375b47f81f46e68cc125d5ef368aa20576ddb53f91f4d83f1d04b929')
+ end
+
+ context 'when mandatory params are not given' do
+ it "responds with a 400 status" do
+ head api(route("any%2Ffile"), current_user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ context 'when file_path does not exist' do
+ it "responds with a 404 status" do
+ params[:ref] = 'master'
+
+ head api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'when file_path does not exist' do
+ include_context 'disabled repository'
+
+ it "responds with a 403 status" do
+ head api(route(file_path), current_user), params
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+
+ context 'when unauthenticated', 'and project is public' do
+ it_behaves_like 'repository files' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:current_user) { nil }
+ end
+ end
+
+ context 'when unauthenticated', 'and project is private' do
+ it "responds with a 404 status" do
+ current_user = nil
+
+ head api(route(file_path), current_user), params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'when authenticated', 'as a developer' do
+ it_behaves_like 'repository files' do
+ let(:current_user) { user }
+ end
+ end
+
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { head api(route(file_path), guest), params }
+ end
+ end
+ end
+
describe "GET /projects/:id/repository/files/:file_path" do
shared_examples_for 'repository files' do
it 'returns file attributes as json' do
@@ -30,6 +113,7 @@ describe API::Files do
expect(json_response['file_path']).to eq(CGI.unescape(file_path))
expect(json_response['file_name']).to eq('popen.rb')
expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
+ expect(json_response['content_sha256']).to eq('c440cd09bae50c4632cc58638ad33c6aa375b6109d811e76a9cc3a613c1e8887')
expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
end
@@ -51,6 +135,7 @@ describe API::Files do
expect(response).to have_gitlab_http_status(200)
expect(json_response['file_name']).to eq('commit.js.coffee')
+ expect(json_response['content_sha256']).to eq('08785f04375b47f81f46e68cc125d5ef368aa20576ddb53f91f4d83f1d04b929')
expect(Base64.decode64(json_response['content']).lines.first).to eq("class Commit\n")
end