summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRebeca Méndez <scullymb@gmail.com>2016-08-29 17:23:40 +0200
committerRebeca Méndez <scullymb@gmail.com>2016-11-12 10:00:39 +0100
commit5c966f70fb218d6f4de0f888733604293f36c33e (patch)
treeecb15585624aaa4c266345e5e65d447f474b817a
parent6eeff67c6e03233d4480a55d05d4e0f1a88aef4c (diff)
downloadgitlab-ce-5c966f70fb218d6f4de0f888733604293f36c33e.tar.gz
Issue #4270: Recursive option for files through API
-rw-r--r--app/models/repository.rb4
-rw-r--r--app/models/tree.rb22
-rw-r--r--changelogs/unreleased/master-recursiveTree.yml4
-rw-r--r--doc/api/repositories.md54
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/api/repositories.rb4
-rw-r--r--spec/requests/api/repositories_spec.rb35
7 files changed, 99 insertions, 26 deletions
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 063dc74021d..4282197faa5 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -631,7 +631,7 @@ class Repository
@head_tree ||= Tree.new(self, head_commit.sha, nil)
end
- def tree(sha = :head, path = nil)
+ def tree(sha = :head, path = nil, recursive: false)
if sha == :head
if path.nil?
return head_tree
@@ -640,7 +640,7 @@ class Repository
end
end
- Tree.new(self, sha, path)
+ Tree.new(self, sha, path, recursive: recursive)
end
def blob_at_branch(branch_name, path)
diff --git a/app/models/tree.rb b/app/models/tree.rb
index 7c4ed6e393b..2d1d68dbd81 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -3,15 +3,16 @@ class Tree
attr_accessor :repository, :sha, :path, :entries
- def initialize(repository, sha, path = '/')
+ def initialize(repository, sha, path = '/', recursive: false)
path = '/' if path.blank?
@repository = repository
@sha = sha
@path = path
+ @recursive = recursive
git_repo = @repository.raw_repository
- @entries = Gitlab::Git::Tree.where(git_repo, @sha, @path)
+ @entries = get_entries(git_repo, @sha, @path, recursive: @recursive)
end
def readme
@@ -58,4 +59,21 @@ class Tree
def sorted_entries
trees + blobs + submodules
end
+
+ private
+
+ def get_entries(git_repo, sha, path, recursive: false)
+ current_path_entries = Gitlab::Git::Tree.where(git_repo, sha, path)
+ ordered_entries = []
+
+ current_path_entries.each do |entry|
+ ordered_entries << entry
+
+ if recursive && entry.dir?
+ ordered_entries.concat(get_entries(git_repo, sha, entry.path, recursive: true))
+ end
+ end
+
+ ordered_entries
+ end
end
diff --git a/changelogs/unreleased/master-recursiveTree.yml b/changelogs/unreleased/master-recursiveTree.yml
new file mode 100644
index 00000000000..c6384d172e2
--- /dev/null
+++ b/changelogs/unreleased/master-recursiveTree.yml
@@ -0,0 +1,4 @@
+---
+title: API: allow recursive tree request
+merge_request: 6088
+author: Rebeca Méndez
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index b6cca5d4e2a..bcf8b955044 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -13,44 +13,58 @@ Parameters:
- `id` (required) - The ID of a project
- `path` (optional) - The path inside repository. Used to get contend of subdirectories
- `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
+- `recursive` (optional) - Boolean value used to get a recursive tree (false by default)
```json
[
{
- "name": "assets",
+ "id": "a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba",
+ "name": "html",
"type": "tree",
- "mode": "040000",
- "id": "6229c43a7e16fcc7e95f923f8ddadb8281d9c6c6"
+ "path": "files/html",
+ "mode": "040000"
},
{
- "name": "contexts",
+ "id": "4535904260b1082e14f867f7a24fd8c21495bde3",
+ "name": "images",
"type": "tree",
- "mode": "040000",
- "id": "faf1cdf33feadc7973118ca42d35f1e62977e91f"
+ "path": "files/images",
+ "mode": "040000"
},
{
- "name": "controllers",
+ "id": "31405c5ddef582c5a9b7a85230413ff90e2fe720",
+ "name": "js",
"type": "tree",
- "mode": "040000",
- "id": "95633e8d258bf3dfba3a5268fb8440d263218d74"
+ "path": "files/js",
+ "mode": "040000"
},
{
- "name": "Rakefile",
- "type": "blob",
- "mode": "100644",
- "id": "35b2f05cbb4566b71b34554cf184a9d0bd9d46d6"
+ "id": "cc71111cfad871212dc99572599a568bfe1e7e00",
+ "name": "lfs",
+ "type": "tree",
+ "path": "files/lfs",
+ "mode": "040000"
},
{
- "name": "VERSION",
- "type": "blob",
- "mode": "100644",
- "id": "803e4a4f3727286c3093c63870c2b6524d30ec4f"
+ "id": "fd581c619bf59cfdfa9c8282377bb09c2f897520",
+ "name": "markdown",
+ "type": "tree",
+ "path": "files/markdown",
+ "mode": "040000"
+ },
+ {
+ "id": "23ea4d11a4bdd960ee5320c5cb65b5b3fdbc60db",
+ "name": "ruby",
+ "type": "tree",
+ "path": "files/ruby",
+ "mode": "040000"
},
{
- "name": "config.ru",
+ "id": "7d70e02340bac451f281cecf0a980907974bd8be",
+ "name": "whitespace",
"type": "blob",
- "mode": "100644",
- "id": "dfd2d862237323aa599be31b473d70a8a817943b"
+ "path": "files/whitespace",
+ "mode": "100644"
}
]
```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 1942aeea656..8f1aaaaaaa0 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -159,7 +159,7 @@ module API
end
class RepoTreeObject < Grape::Entity
- expose :id, :name, :type
+ expose :id, :name, :type, :path
expose :mode do |obj, options|
filemode = obj.mode.to_s(8)
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index f55aceed92c..0bb2f74809a 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -21,16 +21,18 @@ module API
# Parameters:
# id (required) - The ID of a project
# ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
+ # recursive (optional) - Used to get a recursive tree
# Example Request:
# GET /projects/:id/repository/tree
get ':id/repository/tree' do
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
path = params[:path] || nil
+ recursive = to_boolean(params[:recursive])
commit = user_project.commit(ref)
not_found!('Tree') unless commit
- tree = user_project.repository.tree(commit.id, path)
+ tree = user_project.repository.tree(commit.id, path, recursive: recursive)
present tree.sorted_entries, with: Entities::RepoTreeObject
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index c4dc2d9006a..38c8ad34f9d 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -18,6 +18,7 @@ describe API::API, api: true do
it "returns project commits" do
get api("/projects/#{project.id}/repository/tree", user)
+
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
@@ -43,6 +44,40 @@ describe API::API, api: true do
end
end
+
+ describe 'GET /projects/:id/repository/tree?recursive=1' do
+ context 'authorized user' do
+ before { project.team << [user2, :reporter] }
+
+ it 'should return recursive project paths tree' do
+ get api("/projects/#{project.id}/repository/tree?recursive=1", user)
+
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(json_response[4]['name']).to eq('html')
+ expect(json_response[4]['path']).to eq('files/html')
+ expect(json_response[4]['type']).to eq('tree')
+ expect(json_response[4]['mode']).to eq('040000')
+ end
+
+ it 'returns a 404 for unknown ref' do
+ get api("/projects/#{project.id}/repository/tree?ref_name=foo&recursive=1", user)
+ expect(response).to have_http_status(404)
+
+ expect(json_response).to be_an Object
+ json_response['message'] == '404 Tree Not Found'
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not return project commits" do
+ get api("/projects/#{project.id}/repository/tree?recursive=1")
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
describe "GET /projects/:id/repository/blobs/:sha" do
it "gets the raw file contents" do
get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user)