From 8ed228ecec4279e76c757b3b90a24b9810c00de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rebeca=20M=C3=A9ndez?= Date: Mon, 9 Feb 2015 16:45:55 +0100 Subject: [PATCH 1/3] API: allow recursive tree --- CHANGELOG | 56 +++++++++++++------------- app/models/repository.rb | 4 +- app/models/tree.rb | 16 +++++++- doc/api/repositories.md | 7 ++++ lib/api/entities.rb | 2 +- lib/api/repositories.rb | 4 +- spec/requests/api/repositories_spec.rb | 19 ++++++++- 7 files changed, 73 insertions(+), 35 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 74d4031ebaf..70b9132a305 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,60 +13,60 @@ v 7.8.0 - Improve sorting logic in UI and API. Explicitly define what sorting method is used by default - Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger) - Fix overflow at sidebar when have several itens - - + - - Show tags in commit view (Hannes Rosenögger) - Only count a user's vote once on a merge request or issue (Michael Clarke) - - + - - Increate font size when browse source files and diffs - Create new file in empty repository using GitLab UI - - + - - Ability to clone project using oauth2 token - - + - - Upgrade Sidekiq gem to version 3.3.0 - Stop git zombie creation during force push check - Show success/error messages for test setting button in services - Added Rubocop for code style checks - Fix commits pagination - - + - - Async load a branch information at the commit page - Disable blacklist validation for project names - Allow configuring protection of the default branch upon first push (Marco Wessel) - - Add gitlab.com importer - Add an ability to login with gitlab.com - - - - Add a commit calendar to the user profile (Hannes Rosenögger) - - + - + - Add a commit calendar to the user profile (Hannes Rosenögger) + - - Submit comment on command-enter - Notify all members of a group when that group is mentioned in a comment, for example: `@gitlab-org` or `@sales`. - - + - - Fix long broadcast message cut-off on left sidebar (Visay Keo) - Add Project Avatars (Steven Thonus and Hannes Rosenögger) - - - - + - + - - Password reset token validity increased from 2 hours to 2 days since it is also send on account creation. - - - - + - API: Allow recursive tree request + - - Enable raw image paste from clipboard, currently Chrome only (Marco Cyriacks) - - - - + - + - - Add action property to merge request hook (Julien Bianchi) - - + - - Remove duplicates from group milestone participants list. - - - - + - + - - Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger) - - - - + - + - - API: Access groups with their path (Julien Bianchi) - Added link to milestone and keeping resource context on smaller viewports for issues and merge requests (Jason Blanchard) - - + - - Allow notification email to be set separately from primary email. - - - - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger) - - + - + - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger) + - - Don't have Markdown preview fail for long comments/wiki pages. - - + - - When test web hook - show error message instead of 500 error page if connection to hook url was reset - Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov) - Added persistent collapse button for left side nav bar (Jason Blanchard) @@ -106,9 +106,9 @@ v 7.7.0 - When accept merge request - do merge using sidaekiq job - Enable web signups by default - Fixes for diff comments: drag-n-drop images, selecting images - - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update + - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update - Remove password strength indicator - + v 7.6.0 @@ -1129,4 +1129,4 @@ v 0.8.0 - stability - security fixes - increased test coverage - - email notification + - email notification \ No newline at end of file diff --git a/app/models/repository.rb b/app/models/repository.rb index 4e45a6723b8..8560c3a84a4 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -203,12 +203,12 @@ class Repository commit(self.root_ref) end - def tree(sha = :head, path = nil) + def tree(sha = :head, path = nil, recursive = 0) if sha == :head sha = head_commit.sha end - Tree.new(self, sha, path) + Tree.new(self, sha, path, recursive) end def blob_at_branch(branch_name, path) diff --git a/app/models/tree.rb b/app/models/tree.rb index 4f5d81f0a5e..47c36d15f07 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -3,10 +3,11 @@ class Tree attr_accessor :entries, :readme, :contribution_guide - def initialize(repository, sha, path = '/') + def initialize(repository, sha, path = '/', recursive = '0') path = '/' if path.blank? git_repo = repository.raw_repository - @entries = Gitlab::Git::Tree.where(git_repo, sha, path) + + @entries = get_entries(git_repo, sha, path, recursive) available_readmes = @entries.select(&:readme?) @@ -35,6 +36,17 @@ class Tree end end + def get_entries(git_repo, sha, path, recursive = '0') + entries = Gitlab::Git::Tree.where(git_repo, sha, path) + + if recursive == '1' + entries.select(&:dir?).each do |t| + entries += get_entries(git_repo, sha, t.path) + end + end + entries + end + def trees @entries.select(&:dir?) end diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 8acf85d21c8..42455b8adb8 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -90,41 +90,48 @@ 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=1` (optional) - Used to get a recursive tree ```json [ { "name": "assets", + "path": "assets", "type": "tree", "mode": "040000", "id": "6229c43a7e16fcc7e95f923f8ddadb8281d9c6c6" }, { "name": "contexts", + "path": "contexts", "type": "tree", "mode": "040000", "id": "faf1cdf33feadc7973118ca42d35f1e62977e91f" }, { "name": "controllers", + "path": "controllers", "type": "tree", "mode": "040000", "id": "95633e8d258bf3dfba3a5268fb8440d263218d74" }, { "name": "Rakefile", + "path": "Rakefile", "type": "blob", "mode": "100644", "id": "35b2f05cbb4566b71b34554cf184a9d0bd9d46d6" }, { "name": "VERSION", + "path": "VERSION", "type": "blob", "mode": "100644", "id": "803e4a4f3727286c3093c63870c2b6524d30ec4f" }, { "name": "config.ru", + "path": "config.ru", "type": "blob", "mode": "100644", "id": "dfd2d862237323aa599be31b473d70a8a817943b" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index fa76a54c2d8..6d30ea6c398 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -116,7 +116,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 b259914a01c..443e4745ccd 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -56,16 +56,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=1 (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 = params[:recursive] || '0' commit = user_project.repository.commit(ref) not_found!('Tree') unless commit - tree = user_project.repository.tree(commit.id, path) + tree = user_project.repository.tree(commit.id, path, 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 5518d2df566..df1ae9391d6 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -88,7 +88,7 @@ describe API::API, api: true do end end - describe "GET /projects/:id/repository/tree" do + describe 'GET /projects/:id/repository/tree' do context "authorized user" do before { project.team << [user2, :reporter] } @@ -119,6 +119,23 @@ 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 project commits' do + get api("/projects/#{project.id}/repository/tree?recursive=1", user) + response.status.should == 200 + + json_response.should be_an Array + json_response[2]['name'].should == 'html' + json_response[2]['path'].should == 'files/html' + json_response[2]['type'].should == 'tree' + json_response[2]['mode'].should == '040000' + end + end + end + describe "GET /projects/:id/repository/blobs/:sha" do it "should get the raw file contents" do get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user) -- GitLab From 4dd3019f37573cc10281f7b2b785d0f70550d92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rebeca=20M=C3=A9ndez=20Barallobre?= Date: Mon, 9 Feb 2015 17:38:11 +0100 Subject: [PATCH 2/3] test --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 70b9132a305..ab096445c31 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -45,7 +45,7 @@ v 7.8.0 - - - Password reset token validity increased from 2 hours to 2 days since it is also send on account creation. - - API: Allow recursive tree request + - API: Allow recursive tree request - - Enable raw image paste from clipboard, currently Chrome only (Marco Cyriacks) - @@ -1129,4 +1129,4 @@ v 0.8.0 - stability - security fixes - increased test coverage - - email notification \ No newline at end of file + - email notification -- GitLab From 2852b043e828d7e2a3f86d1b83398fd1dca20c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rebeca=20M=C3=A9ndez?= Date: Mon, 9 Feb 2015 16:45:55 +0100 Subject: [PATCH 3/3] API: allow recursive tree --- CHANGELOG | 54 +++++++++++++------------- app/models/repository.rb | 4 +- app/models/tree.rb | 16 +++++++- doc/api/repositories.md | 7 ++++ lib/api/entities.rb | 2 +- lib/api/repositories.rb | 4 +- spec/requests/api/repositories_spec.rb | 19 ++++++++- 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 74d4031ebaf..ab096445c31 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,60 +13,60 @@ v 7.8.0 - Improve sorting logic in UI and API. Explicitly define what sorting method is used by default - Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger) - Fix overflow at sidebar when have several itens - - + - - Show tags in commit view (Hannes Rosenögger) - Only count a user's vote once on a merge request or issue (Michael Clarke) - - + - - Increate font size when browse source files and diffs - Create new file in empty repository using GitLab UI - - + - - Ability to clone project using oauth2 token - - + - - Upgrade Sidekiq gem to version 3.3.0 - Stop git zombie creation during force push check - Show success/error messages for test setting button in services - Added Rubocop for code style checks - Fix commits pagination - - + - - Async load a branch information at the commit page - Disable blacklist validation for project names - Allow configuring protection of the default branch upon first push (Marco Wessel) - - Add gitlab.com importer - Add an ability to login with gitlab.com - - - - Add a commit calendar to the user profile (Hannes Rosenögger) - - + - + - Add a commit calendar to the user profile (Hannes Rosenögger) + - - Submit comment on command-enter - Notify all members of a group when that group is mentioned in a comment, for example: `@gitlab-org` or `@sales`. - - + - - Fix long broadcast message cut-off on left sidebar (Visay Keo) - Add Project Avatars (Steven Thonus and Hannes Rosenögger) - - - - + - + - - Password reset token validity increased from 2 hours to 2 days since it is also send on account creation. - - - - + - API: Allow recursive tree request + - - Enable raw image paste from clipboard, currently Chrome only (Marco Cyriacks) - - - - + - + - - Add action property to merge request hook (Julien Bianchi) - - + - - Remove duplicates from group milestone participants list. - - - - + - + - - Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger) - - - - + - + - - API: Access groups with their path (Julien Bianchi) - Added link to milestone and keeping resource context on smaller viewports for issues and merge requests (Jason Blanchard) - - + - - Allow notification email to be set separately from primary email. - - - - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger) - - + - + - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger) + - - Don't have Markdown preview fail for long comments/wiki pages. - - + - - When test web hook - show error message instead of 500 error page if connection to hook url was reset - Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov) - Added persistent collapse button for left side nav bar (Jason Blanchard) @@ -106,9 +106,9 @@ v 7.7.0 - When accept merge request - do merge using sidaekiq job - Enable web signups by default - Fixes for diff comments: drag-n-drop images, selecting images - - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update + - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update - Remove password strength indicator - + v 7.6.0 diff --git a/app/models/repository.rb b/app/models/repository.rb index 4e45a6723b8..8560c3a84a4 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -203,12 +203,12 @@ class Repository commit(self.root_ref) end - def tree(sha = :head, path = nil) + def tree(sha = :head, path = nil, recursive = 0) if sha == :head sha = head_commit.sha end - Tree.new(self, sha, path) + Tree.new(self, sha, path, recursive) end def blob_at_branch(branch_name, path) diff --git a/app/models/tree.rb b/app/models/tree.rb index 4f5d81f0a5e..47c36d15f07 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -3,10 +3,11 @@ class Tree attr_accessor :entries, :readme, :contribution_guide - def initialize(repository, sha, path = '/') + def initialize(repository, sha, path = '/', recursive = '0') path = '/' if path.blank? git_repo = repository.raw_repository - @entries = Gitlab::Git::Tree.where(git_repo, sha, path) + + @entries = get_entries(git_repo, sha, path, recursive) available_readmes = @entries.select(&:readme?) @@ -35,6 +36,17 @@ class Tree end end + def get_entries(git_repo, sha, path, recursive = '0') + entries = Gitlab::Git::Tree.where(git_repo, sha, path) + + if recursive == '1' + entries.select(&:dir?).each do |t| + entries += get_entries(git_repo, sha, t.path) + end + end + entries + end + def trees @entries.select(&:dir?) end diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 8acf85d21c8..42455b8adb8 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -90,41 +90,48 @@ 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=1` (optional) - Used to get a recursive tree ```json [ { "name": "assets", + "path": "assets", "type": "tree", "mode": "040000", "id": "6229c43a7e16fcc7e95f923f8ddadb8281d9c6c6" }, { "name": "contexts", + "path": "contexts", "type": "tree", "mode": "040000", "id": "faf1cdf33feadc7973118ca42d35f1e62977e91f" }, { "name": "controllers", + "path": "controllers", "type": "tree", "mode": "040000", "id": "95633e8d258bf3dfba3a5268fb8440d263218d74" }, { "name": "Rakefile", + "path": "Rakefile", "type": "blob", "mode": "100644", "id": "35b2f05cbb4566b71b34554cf184a9d0bd9d46d6" }, { "name": "VERSION", + "path": "VERSION", "type": "blob", "mode": "100644", "id": "803e4a4f3727286c3093c63870c2b6524d30ec4f" }, { "name": "config.ru", + "path": "config.ru", "type": "blob", "mode": "100644", "id": "dfd2d862237323aa599be31b473d70a8a817943b" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index fa76a54c2d8..6d30ea6c398 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -116,7 +116,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 b259914a01c..443e4745ccd 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -56,16 +56,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=1 (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 = params[:recursive] || '0' commit = user_project.repository.commit(ref) not_found!('Tree') unless commit - tree = user_project.repository.tree(commit.id, path) + tree = user_project.repository.tree(commit.id, path, 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 5518d2df566..df1ae9391d6 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -88,7 +88,7 @@ describe API::API, api: true do end end - describe "GET /projects/:id/repository/tree" do + describe 'GET /projects/:id/repository/tree' do context "authorized user" do before { project.team << [user2, :reporter] } @@ -119,6 +119,23 @@ 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 project commits' do + get api("/projects/#{project.id}/repository/tree?recursive=1", user) + response.status.should == 200 + + json_response.should be_an Array + json_response[2]['name'].should == 'html' + json_response[2]['path'].should == 'files/html' + json_response[2]['type'].should == 'tree' + json_response[2]['mode'].should == '040000' + end + end + end + describe "GET /projects/:id/repository/blobs/:sha" do it "should get the raw file contents" do get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user) -- GitLab