summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/commits.rb28
-rw-r--r--lib/api/jobs.rb39
-rw-r--r--lib/api/v3/builds.rb24
-rw-r--r--lib/gitlab/git/repository.rb12
-rw-r--r--lib/gitlab/middleware/go.rb66
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