diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/commits.rb | 28 | ||||
-rw-r--r-- | lib/api/jobs.rb | 39 | ||||
-rw-r--r-- | lib/api/v3/builds.rb | 24 | ||||
-rw-r--r-- | lib/gitlab/git/repository.rb | 12 | ||||
-rw-r--r-- | lib/gitlab/middleware/go.rb | 66 |
5 files changed, 122 insertions, 47 deletions
diff --git a/lib/api/commits.rb b/lib/api/commits.rb index b0aa10f8bf2..42401abfe0f 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -18,22 +18,34 @@ module API optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used' optional :since, type: DateTime, desc: 'Only commits after or on this date will be returned' optional :until, type: DateTime, desc: 'Only commits before or on this date will be returned' - optional :page, type: Integer, default: 0, desc: 'The page for pagination' - optional :per_page, type: Integer, default: 20, desc: 'The number of results per page' optional :path, type: String, desc: 'The file path' + use :pagination end get ":id/repository/commits" do - ref = params[:ref_name] || user_project.try(:default_branch) || 'master' - offset = params[:page] * params[:per_page] + path = params[:path] + before = params[:until] + after = params[:since] + ref = params[:ref_name] || user_project.try(:default_branch) || 'master' + offset = (params[:page] - 1) * params[:per_page] commits = user_project.repository.commits(ref, - path: params[:path], + path: path, limit: params[:per_page], offset: offset, - after: params[:since], - before: params[:until]) + before: before, + after: after) + + commit_count = + if path || before || after + user_project.repository.count_commits(ref: ref, path: path, before: before, after: after) + else + # Cacheable commit count. + user_project.repository.commit_count_for_ref(ref) + end + + paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count) - present commits, with: Entities::RepoCommit + present paginate(paginated_commits), with: Entities::RepoCommit end desc 'Commit multiple file changes as one commit' do diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index 33c05e8aa63..44118522abe 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -18,6 +18,8 @@ module API [scope] when Hashie::Mash scope.values + when Hashie::Array + scope else ['unknown'] end @@ -36,8 +38,23 @@ module API builds = user_project.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) - present paginate(builds), with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present paginate(builds), with: Entities::Job + end + + desc 'Get pipeline jobs' do + success Entities::Job + end + params do + requires :pipeline_id, type: Integer, desc: 'The pipeline ID' + use :optional_scope + use :pagination + end + get ':id/pipelines/:pipeline_id/jobs' do + pipeline = user_project.pipelines.find(params[:pipeline_id]) + builds = pipeline.builds + builds = filter_builds(builds, params[:scope]) + + present paginate(builds), with: Entities::Job end desc 'Get a specific job of a project' do @@ -51,8 +68,7 @@ module API build = get_build!(params[:job_id]) - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: Entities::Job end desc 'Download the artifacts file from a job' do @@ -119,8 +135,7 @@ module API build.cancel - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: Entities::Job end desc 'Retry a specific build of a project' do @@ -137,8 +152,7 @@ module API build = Ci::Build.retry(build, current_user) - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: Entities::Job end desc 'Erase job (remove artifacts and the trace)' do @@ -154,8 +168,7 @@ module API return forbidden!('Job is not erasable!') unless build.erasable? build.erase(erased_by: current_user) - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) + present build, with: Entities::Job end desc 'Keep the artifacts to prevent them from being deleted' do @@ -173,8 +186,7 @@ module API build.keep_artifacts! status 200 - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: Entities::Job end desc 'Trigger a manual job' do @@ -194,8 +206,7 @@ module API build.play(current_user) status 200 - present build, with: Entities::Job, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: Entities::Job end end diff --git a/lib/api/v3/builds.rb b/lib/api/v3/builds.rb index c8feba13527..6f97102c6ef 100644 --- a/lib/api/v3/builds.rb +++ b/lib/api/v3/builds.rb @@ -36,8 +36,7 @@ module API builds = user_project.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) - present paginate(builds), with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present paginate(builds), with: ::API::V3::Entities::Build end desc 'Get builds for a specific commit of a project' do @@ -57,8 +56,7 @@ module API builds = user_project.builds.where(pipeline: pipelines).order('id DESC') builds = filter_builds(builds, params[:scope]) - present paginate(builds), with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present paginate(builds), with: ::API::V3::Entities::Build end desc 'Get a specific build of a project' do @@ -72,8 +70,7 @@ module API build = get_build!(params[:build_id]) - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: ::API::V3::Entities::Build end desc 'Download the artifacts file from build' do @@ -140,8 +137,7 @@ module API build.cancel - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: ::API::V3::Entities::Build end desc 'Retry a specific build of a project' do @@ -158,8 +154,7 @@ module API build = Ci::Build.retry(build, current_user) - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: ::API::V3::Entities::Build end desc 'Erase build (remove artifacts and build trace)' do @@ -175,8 +170,7 @@ module API return forbidden!('Build is not erasable!') unless build.erasable? build.erase(erased_by: current_user) - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) + present build, with: ::API::V3::Entities::Build end desc 'Keep the artifacts to prevent them from being deleted' do @@ -194,8 +188,7 @@ module API build.keep_artifacts! status 200 - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: ::API::V3::Entities::Build end desc 'Trigger a manual build' do @@ -215,8 +208,7 @@ module API build.play(current_user) status 200 - present build, with: ::API::V3::Entities::Build, - user_can_download_artifacts: can?(current_user, :read_build, user_project) + present build, with: ::API::V3::Entities::Build end end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 6540730ca7a..228ef7bb7a9 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -354,6 +354,18 @@ module Gitlab lines.map! { |c| Rugged::Commit.new(rugged, c.strip) } end + def count_commits(options) + cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list] + cmd << "--after=#{options[:after].iso8601}" if options[:after] + cmd << "--before=#{options[:before].iso8601}" if options[:before] + cmd += %W[--count #{options[:ref]}] + cmd += %W[-- #{options[:path]}] if options[:path].present? + + raw_output = IO.popen(cmd) { |io| io.read } + + raw_output.to_i + end + def sha_from_ref(ref) rev_parse_target(ref).oid end diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb index 5764ab15652..6023fa1820f 100644 --- a/lib/gitlab/middleware/go.rb +++ b/lib/gitlab/middleware/go.rb @@ -30,21 +30,69 @@ module Gitlab end def go_body(request) - base_url = Gitlab.config.gitlab.url - # Go subpackages may be in the form of namespace/project/path1/path2/../pathN - # We can just ignore the paths and leave the namespace/project - path_info = request.env["PATH_INFO"] - path_info.sub!(/^\//, '') - project_path = path_info.split('/').first(2).join('/') - request_url = URI.join(base_url, project_path) - domain_path = strip_url(request_url.to_s) + project_url = URI.join(Gitlab.config.gitlab.url, project_path(request)) + import_prefix = strip_url(project_url.to_s) - "<!DOCTYPE html><html><head><meta content='#{domain_path} git #{request_url}.git' name='go-import'></head></html>\n" + "<!DOCTYPE html><html><head><meta content='#{import_prefix} git #{project_url}.git' name='go-import'></head></html>\n" end def strip_url(url) url.gsub(/\Ahttps?:\/\//, '') end + + def project_path(request) + path_info = request.env["PATH_INFO"] + path_info.sub!(/^\//, '') + + # Go subpackages may be in the form of `namespace/project/path1/path2/../pathN`. + # In a traditional project with a single namespace, this would denote repo + # `namespace/project` with subpath `path1/path2/../pathN`, but with nested + # groups, this could also be `namespace/project/path1` with subpath + # `path2/../pathN`, for example. + + # We find all potential project paths out of the path segments + path_segments = path_info.split('/') + simple_project_path = path_segments.first(2).join('/') + + # If the path is at most 2 segments long, it is a simple `namespace/project` path and we're done + return simple_project_path if path_segments.length <= 2 + + project_paths = [] + begin + project_paths << path_segments.join('/') + path_segments.pop + end while path_segments.length >= 2 + + # We see if a project exists with any of these potential paths + project = project_for_paths(project_paths, request) + + if project + # If a project is found and the user has access, we return the full project path + project.full_path + else + # If not, we return the first two components as if it were a simple `namespace/project` path, + # so that we don't reveal the existence of a nested project the user doesn't have access to. + # This means that for an unauthenticated request to `group/subgroup/project/subpackage` + # for a private `group/subgroup/project` with subpackage path `subpackage`, GitLab will respond + # as if the user is looking for project `group/subgroup`, with subpackage path `project/subpackage`. + # Since `go get` doesn't authenticate by default, this means that + # `go get gitlab.com/group/subgroup/project/subpackage` will not work for private projects. + # `go get gitlab.com/group/subgroup/project.git/subpackage` will work, since Go is smart enough + # to figure that out. `import 'gitlab.com/...'` behaves the same as `go get`. + simple_project_path + end + end + + def project_for_paths(paths, request) + project = Project.where_full_path_in(paths).first + return unless Ability.allowed?(current_user(request), :read_project, project) + + project + end + + def current_user(request) + request.env['warden']&.authenticate + end end end end |