Commit ddbe978041753d7851780165f8c6c66865570862
1 parent
87a449f2
Exists in
spb-stable
and in
3 other branches
Complete api files CRUD
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Showing
7 changed files
with
192 additions
and
49 deletions
Show diff stats
app/models/repository.rb
| @@ -180,13 +180,13 @@ class Repository | @@ -180,13 +180,13 @@ class Repository | ||
| 180 | end | 180 | end |
| 181 | 181 | ||
| 182 | def blob_at_branch(branch_name, path) | 182 | def blob_at_branch(branch_name, path) |
| 183 | - last_commit = commit(branch_name) | 183 | + last_commit = commit(branch_name) |
| 184 | 184 | ||
| 185 | - if last_commit | ||
| 186 | - blob_at(last_commit.sha, path) | ||
| 187 | - else | ||
| 188 | - nil | ||
| 189 | - end | 185 | + if last_commit |
| 186 | + blob_at(last_commit.sha, path) | ||
| 187 | + else | ||
| 188 | + nil | ||
| 189 | + end | ||
| 190 | end | 190 | end |
| 191 | 191 | ||
| 192 | # Returns url for submodule | 192 | # Returns url for submodule |
app/views/help/_api_layout.html.haml
| @@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
| 5 | %i.icon-angle-left | 5 | %i.icon-angle-left |
| 6 | Back to help | 6 | Back to help |
| 7 | %ul.nav.nav-pills.nav-stacked | 7 | %ul.nav.nav-pills.nav-stacked |
| 8 | - - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| | 8 | + - %w(README projects project_snippets repositories repository_files deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| |
| 9 | %li{class: file == @category ? 'active' : nil} | 9 | %li{class: file == @category ? 'active' : nil} |
| 10 | = link_to file.titleize, help_api_file_path(file) | 10 | = link_to file.titleize, help_api_file_path(file) |
| 11 | 11 |
doc/api/README.md
| @@ -127,6 +127,7 @@ But when you want to create a link to web page - use `http:://host/project/issu | @@ -127,6 +127,7 @@ But when you want to create a link to web page - use `http:://host/project/issu | ||
| 127 | + [Projects](projects.md) | 127 | + [Projects](projects.md) |
| 128 | + [Project Snippets](project_snippets.md) | 128 | + [Project Snippets](project_snippets.md) |
| 129 | + [Repositories](repositories.md) | 129 | + [Repositories](repositories.md) |
| 130 | ++ [Repository Files](repository_files.md) | ||
| 130 | + [Merge Requests](merge_requests.md) | 131 | + [Merge Requests](merge_requests.md) |
| 131 | + [Issues](issues.md) | 132 | + [Issues](issues.md) |
| 132 | + [Milestones](milestones.md) | 133 | + [Milestones](milestones.md) |
doc/api/repositories.md
| @@ -388,44 +388,3 @@ GET /projects/:id/repository/archive | @@ -388,44 +388,3 @@ GET /projects/:id/repository/archive | ||
| 388 | Parameters: | 388 | Parameters: |
| 389 | + `id` (required) - The ID of a project | 389 | + `id` (required) - The ID of a project |
| 390 | + `sha` (optional) - The commit sha to download defaults to the tip of the default branch | 390 | + `sha` (optional) - The commit sha to download defaults to the tip of the default branch |
| 391 | - | ||
| 392 | - | ||
| 393 | -## Create new file in repository | ||
| 394 | - | ||
| 395 | -``` | ||
| 396 | -POST /projects/:id/repository/files | ||
| 397 | -``` | ||
| 398 | - | ||
| 399 | -Parameters: | ||
| 400 | - | ||
| 401 | -+ `file_path` (optional) - Full path to new file. Ex. lib/class.rb | ||
| 402 | -+ `branch_name` (required) - The name of branch | ||
| 403 | -+ `encoding` (optional) - 'text' or 'base64'. Text is default. | ||
| 404 | -+ `content` (required) - File content | ||
| 405 | -+ `commit_message` (required) - Commit message | ||
| 406 | - | ||
| 407 | -## Update existing file in repository | ||
| 408 | - | ||
| 409 | -``` | ||
| 410 | -PUT /projects/:id/repository/files | ||
| 411 | -``` | ||
| 412 | - | ||
| 413 | -Parameters: | ||
| 414 | - | ||
| 415 | -+ `file_path` (required) - Full path to file. Ex. lib/class.rb | ||
| 416 | -+ `branch_name` (required) - The name of branch | ||
| 417 | -+ `encoding` (optional) - 'text' or 'base64'. Text is default. | ||
| 418 | -+ `content` (required) - New file content | ||
| 419 | -+ `commit_message` (required) - Commit message | ||
| 420 | - | ||
| 421 | -## Delete existing file in repository | ||
| 422 | - | ||
| 423 | -``` | ||
| 424 | -DELETE /projects/:id/repository/files | ||
| 425 | -``` | ||
| 426 | - | ||
| 427 | -Parameters: | ||
| 428 | - | ||
| 429 | -+ `file_path` (required) - Full path to file. Ex. lib/class.rb | ||
| 430 | -+ `branch_name` (required) - The name of branch | ||
| 431 | -+ `commit_message` (required) - Commit message |
| @@ -0,0 +1,102 @@ | @@ -0,0 +1,102 @@ | ||
| 1 | +# CRUD for repository files | ||
| 2 | + | ||
| 3 | +## Create, read, update and delete repository files using this API | ||
| 4 | + | ||
| 5 | +- - - | ||
| 6 | + | ||
| 7 | +## Get file from repository | ||
| 8 | + | ||
| 9 | +Allows you to receive information about file in repository like name, size, content. | ||
| 10 | +Note that file content is Base64 encoded. | ||
| 11 | + | ||
| 12 | +``` | ||
| 13 | +GET /projects/:id/repository/files | ||
| 14 | +``` | ||
| 15 | + | ||
| 16 | +Example response: | ||
| 17 | + | ||
| 18 | +```json | ||
| 19 | +{ | ||
| 20 | + "file_name": "key.rb", | ||
| 21 | + "file_path": "app/models/key.rb", | ||
| 22 | + "size": 1476, | ||
| 23 | + "encoding": "base64", | ||
| 24 | + "content": "IyA9PSBTY2hlbWEgSW5mb3...", | ||
| 25 | + "ref": "master", | ||
| 26 | + "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", | ||
| 27 | + "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" | ||
| 28 | +} | ||
| 29 | +``` | ||
| 30 | + | ||
| 31 | +Parameters: | ||
| 32 | + | ||
| 33 | ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb | ||
| 34 | ++ `ref` (required) - The name of branch, tag or commit | ||
| 35 | + | ||
| 36 | +## Create new file in repository | ||
| 37 | + | ||
| 38 | +``` | ||
| 39 | +POST /projects/:id/repository/files | ||
| 40 | +``` | ||
| 41 | + | ||
| 42 | +Example response: | ||
| 43 | + | ||
| 44 | +```json | ||
| 45 | +{ | ||
| 46 | + "file_name": "app/project.rb", | ||
| 47 | + "branch_name": "master", | ||
| 48 | +} | ||
| 49 | +``` | ||
| 50 | + | ||
| 51 | +Parameters: | ||
| 52 | + | ||
| 53 | ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb | ||
| 54 | ++ `branch_name` (required) - The name of branch | ||
| 55 | ++ `encoding` (optional) - 'text' or 'base64'. Text is default. | ||
| 56 | ++ `content` (required) - File content | ||
| 57 | ++ `commit_message` (required) - Commit message | ||
| 58 | + | ||
| 59 | +## Update existing file in repository | ||
| 60 | + | ||
| 61 | +``` | ||
| 62 | +PUT /projects/:id/repository/files | ||
| 63 | +``` | ||
| 64 | + | ||
| 65 | +Example response: | ||
| 66 | + | ||
| 67 | +```json | ||
| 68 | +{ | ||
| 69 | + "file_name": "app/project.rb", | ||
| 70 | + "branch_name": "master", | ||
| 71 | +} | ||
| 72 | +``` | ||
| 73 | + | ||
| 74 | +Parameters: | ||
| 75 | + | ||
| 76 | ++ `file_path` (required) - Full path to file. Ex. lib/class.rb | ||
| 77 | ++ `branch_name` (required) - The name of branch | ||
| 78 | ++ `encoding` (optional) - 'text' or 'base64'. Text is default. | ||
| 79 | ++ `content` (required) - New file content | ||
| 80 | ++ `commit_message` (required) - Commit message | ||
| 81 | + | ||
| 82 | +## Delete existing file in repository | ||
| 83 | + | ||
| 84 | +``` | ||
| 85 | +DELETE /projects/:id/repository/files | ||
| 86 | +``` | ||
| 87 | + | ||
| 88 | +Example response: | ||
| 89 | + | ||
| 90 | +```json | ||
| 91 | +{ | ||
| 92 | + "file_name": "app/project.rb", | ||
| 93 | + "branch_name": "master", | ||
| 94 | +} | ||
| 95 | +``` | ||
| 96 | + | ||
| 97 | +Parameters: | ||
| 98 | + | ||
| 99 | ++ `file_path` (required) - Full path to file. Ex. lib/class.rb | ||
| 100 | ++ `branch_name` (required) - The name of branch | ||
| 101 | ++ `commit_message` (required) - Commit message | ||
| 102 | + |
lib/api/files.rb
| @@ -5,10 +5,61 @@ module API | @@ -5,10 +5,61 @@ module API | ||
| 5 | before { authorize! :push_code, user_project } | 5 | before { authorize! :push_code, user_project } |
| 6 | 6 | ||
| 7 | resource :projects do | 7 | resource :projects do |
| 8 | + # Get file from repository | ||
| 9 | + # File content is Base64 encoded | ||
| 10 | + # | ||
| 11 | + # Parameters: | ||
| 12 | + # file_path (required) - The path to the file. Ex. lib/class.rb | ||
| 13 | + # ref (required) - The name of branch, tag or commit | ||
| 14 | + # | ||
| 15 | + # Example Request: | ||
| 16 | + # GET /projects/:id/repository/files | ||
| 17 | + # | ||
| 18 | + # Example response: | ||
| 19 | + # { | ||
| 20 | + # "file_name": "key.rb", | ||
| 21 | + # "file_path": "app/models/key.rb", | ||
| 22 | + # "size": 1476, | ||
| 23 | + # "encoding": "base64", | ||
| 24 | + # "content": "IyA9PSBTY2hlbWEgSW5mb3...", | ||
| 25 | + # "ref": "master", | ||
| 26 | + # "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", | ||
| 27 | + # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" | ||
| 28 | + # } | ||
| 29 | + # | ||
| 30 | + get ":id/repository/files" do | ||
| 31 | + required_attributes! [:file_path, :ref] | ||
| 32 | + attrs = attributes_for_keys [:file_path, :ref] | ||
| 33 | + ref = attrs.delete(:ref) | ||
| 34 | + file_path = attrs.delete(:file_path) | ||
| 35 | + | ||
| 36 | + commit = user_project.repository.commit(ref) | ||
| 37 | + not_found! "Commit" unless commit | ||
| 38 | + | ||
| 39 | + blob = user_project.repository.blob_at(commit.sha, file_path) | ||
| 40 | + | ||
| 41 | + if blob | ||
| 42 | + status(200) | ||
| 43 | + | ||
| 44 | + { | ||
| 45 | + file_name: blob.name, | ||
| 46 | + file_path: blob.path, | ||
| 47 | + size: blob.size, | ||
| 48 | + encoding: "base64", | ||
| 49 | + content: Base64.encode64(blob.data), | ||
| 50 | + ref: ref, | ||
| 51 | + blob_id: blob.id, | ||
| 52 | + commit_id: commit.id, | ||
| 53 | + } | ||
| 54 | + else | ||
| 55 | + render_api_error!('File not found', 404) | ||
| 56 | + end | ||
| 57 | + end | ||
| 58 | + | ||
| 8 | # Create new file in repository | 59 | # Create new file in repository |
| 9 | # | 60 | # |
| 10 | # Parameters: | 61 | # Parameters: |
| 11 | - # file_path (optional) - The path to new file. Ex. lib/class.rb | 62 | + # file_path (required) - The path to new file. Ex. lib/class.rb |
| 12 | # branch_name (required) - The name of branch | 63 | # branch_name (required) - The name of branch |
| 13 | # content (required) - File content | 64 | # content (required) - File content |
| 14 | # commit_message (required) - Commit message | 65 | # commit_message (required) - Commit message |
spec/requests/api/files_spec.rb
| @@ -9,6 +9,36 @@ describe API::API do | @@ -9,6 +9,36 @@ describe API::API do | ||
| 9 | let!(:project) { create(:project, namespace: user.namespace ) } | 9 | let!(:project) { create(:project, namespace: user.namespace ) } |
| 10 | before { project.team << [user, :developer] } | 10 | before { project.team << [user, :developer] } |
| 11 | 11 | ||
| 12 | + describe "GET /projects/:id/repository/files" do | ||
| 13 | + it "should return file info" do | ||
| 14 | + params = { | ||
| 15 | + file_path: 'app/models/key.rb', | ||
| 16 | + ref: 'master', | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + get api("/projects/#{project.id}/repository/files", user), params | ||
| 20 | + response.status.should == 200 | ||
| 21 | + json_response['file_path'].should == 'app/models/key.rb' | ||
| 22 | + json_response['file_name'].should == 'key.rb' | ||
| 23 | + Base64.decode64(json_response['content']).lines.first.should == "class Key < ActiveRecord::Base\n" | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + it "should return a 400 bad request if no params given" do | ||
| 27 | + get api("/projects/#{project.id}/repository/files", user) | ||
| 28 | + response.status.should == 400 | ||
| 29 | + end | ||
| 30 | + | ||
| 31 | + it "should return a 404 if such file does not exist" do | ||
| 32 | + params = { | ||
| 33 | + file_path: 'app/models/application.rb', | ||
| 34 | + ref: 'master', | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + get api("/projects/#{project.id}/repository/files", user), params | ||
| 38 | + response.status.should == 404 | ||
| 39 | + end | ||
| 40 | + end | ||
| 41 | + | ||
| 12 | describe "POST /projects/:id/repository/files" do | 42 | describe "POST /projects/:id/repository/files" do |
| 13 | let(:valid_params) { | 43 | let(:valid_params) { |
| 14 | { | 44 | { |