diff --git a/app/models/repository.rb b/app/models/repository.rb index 2c2bf242b94..99d908b5d81 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -180,13 +180,13 @@ class Repository end def blob_at_branch(branch_name, path) - last_commit = commit(branch_name) + last_commit = commit(branch_name) - if last_commit - blob_at(last_commit.sha, path) - else - nil - end + if last_commit + blob_at(last_commit.sha, path) + else + nil + end end # Returns url for submodule diff --git a/app/views/help/_api_layout.html.haml b/app/views/help/_api_layout.html.haml index c211b658410..9f7bc78355e 100644 --- a/app/views/help/_api_layout.html.haml +++ b/app/views/help/_api_layout.html.haml @@ -5,7 +5,7 @@ %i.icon-angle-left Back to help %ul.nav.nav-pills.nav-stacked - - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| + - %w(README projects project_snippets repositories repository_files deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file| %li{class: file == @category ? 'active' : nil} = link_to file.titleize, help_api_file_path(file) diff --git a/doc/api/README.md b/doc/api/README.md index 517a9fae6f6..f13f319a843 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -127,6 +127,7 @@ But when you want to create a link to web page - use `http:://host/project/issu + [Projects](projects.md) + [Project Snippets](project_snippets.md) + [Repositories](repositories.md) ++ [Repository Files](repository_files.md) + [Merge Requests](merge_requests.md) + [Issues](issues.md) + [Milestones](milestones.md) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 01607263008..70e297f1bcb 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -388,44 +388,3 @@ GET /projects/:id/repository/archive Parameters: + `id` (required) - The ID of a project + `sha` (optional) - The commit sha to download defaults to the tip of the default branch - - -## Create new file in repository - -``` -POST /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (optional) - Full path to new file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `encoding` (optional) - 'text' or 'base64'. Text is default. -+ `content` (required) - File content -+ `commit_message` (required) - Commit message - -## Update existing file in repository - -``` -PUT /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (required) - Full path to file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `encoding` (optional) - 'text' or 'base64'. Text is default. -+ `content` (required) - New file content -+ `commit_message` (required) - Commit message - -## Delete existing file in repository - -``` -DELETE /projects/:id/repository/files -``` - -Parameters: - -+ `file_path` (required) - Full path to file. Ex. lib/class.rb -+ `branch_name` (required) - The name of branch -+ `commit_message` (required) - Commit message diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md new file mode 100644 index 00000000000..cafab8c828f --- /dev/null +++ b/doc/api/repository_files.md @@ -0,0 +1,102 @@ +# CRUD for repository files + +## Create, read, update and delete repository files using this API + +- - - + +## Get file from repository + +Allows you to receive information about file in repository like name, size, content. +Note that file content is Base64 encoded. + +``` +GET /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "key.rb", + "file_path": "app/models/key.rb", + "size": 1476, + "encoding": "base64", + "content": "IyA9PSBTY2hlbWEgSW5mb3...", + "ref": "master", + "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", + "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" +} +``` + +Parameters: + ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb ++ `ref` (required) - The name of branch, tag or commit + +## Create new file in repository + +``` +POST /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to new file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `encoding` (optional) - 'text' or 'base64'. Text is default. ++ `content` (required) - File content ++ `commit_message` (required) - Commit message + +## Update existing file in repository + +``` +PUT /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `encoding` (optional) - 'text' or 'base64'. Text is default. ++ `content` (required) - New file content ++ `commit_message` (required) - Commit message + +## Delete existing file in repository + +``` +DELETE /projects/:id/repository/files +``` + +Example response: + +```json +{ + "file_name": "app/project.rb", + "branch_name": "master", +} +``` + +Parameters: + ++ `file_path` (required) - Full path to file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `commit_message` (required) - Commit message + diff --git a/lib/api/files.rb b/lib/api/files.rb index 213604915a6..e0c46f92b84 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -5,10 +5,61 @@ module API before { authorize! :push_code, user_project } resource :projects do + # Get file from repository + # File content is Base64 encoded + # + # Parameters: + # file_path (required) - The path to the file. Ex. lib/class.rb + # ref (required) - The name of branch, tag or commit + # + # Example Request: + # GET /projects/:id/repository/files + # + # Example response: + # { + # "file_name": "key.rb", + # "file_path": "app/models/key.rb", + # "size": 1476, + # "encoding": "base64", + # "content": "IyA9PSBTY2hlbWEgSW5mb3...", + # "ref": "master", + # "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", + # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" + # } + # + get ":id/repository/files" do + required_attributes! [:file_path, :ref] + attrs = attributes_for_keys [:file_path, :ref] + ref = attrs.delete(:ref) + file_path = attrs.delete(:file_path) + + commit = user_project.repository.commit(ref) + not_found! "Commit" unless commit + + blob = user_project.repository.blob_at(commit.sha, file_path) + + if blob + status(200) + + { + file_name: blob.name, + file_path: blob.path, + size: blob.size, + encoding: "base64", + content: Base64.encode64(blob.data), + ref: ref, + blob_id: blob.id, + commit_id: commit.id, + } + else + render_api_error!('File not found', 404) + end + end + # Create new file in repository # # Parameters: - # file_path (optional) - The path to new file. Ex. lib/class.rb + # file_path (required) - The path to new file. Ex. lib/class.rb # branch_name (required) - The name of branch # content (required) - File content # commit_message (required) - Commit message diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index acef7df8777..fa25a4bec6a 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -9,6 +9,36 @@ describe API::API do let!(:project) { create(:project, namespace: user.namespace ) } before { project.team << [user, :developer] } + describe "GET /projects/:id/repository/files" do + it "should return file info" do + params = { + file_path: 'app/models/key.rb', + ref: 'master', + } + + get api("/projects/#{project.id}/repository/files", user), params + response.status.should == 200 + json_response['file_path'].should == 'app/models/key.rb' + json_response['file_name'].should == 'key.rb' + Base64.decode64(json_response['content']).lines.first.should == "class Key < ActiveRecord::Base\n" + end + + it "should return a 400 bad request if no params given" do + get api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 404 if such file does not exist" do + params = { + file_path: 'app/models/application.rb', + ref: 'master', + } + + get api("/projects/#{project.id}/repository/files", user), params + response.status.should == 404 + end + end + describe "POST /projects/:id/repository/files" do let(:valid_params) { {